Files
DongHyeonkaandClaude Opus 5 ef947e5bb0 refactor(build,ci): 현재 상태 검증을 걷어내고 불변조건만 남기는 검증 표면 축소
외부 리뷰("현재 상태를 유지하기 위한 검증이 너무 많고, 그 검증 자체를
다시 검증하는 구조까지 생겼다")를 설계 문서로 정리하고 코드로 반영한다.
설계·판단 근거는 docs/superpowers/specs/2026-09-16-verification-surface-reduction-design.md.

삭제
- .github/ci-gate-matrix.yml(1,025줄) + verify-gate-matrix.sh(568줄):
  Gradle task graph와 workflow graph에 이미 있는 정보의 3중 복제
- verify-gradle-wrapper.sh(799줄): workflow 바이트 해시 잠금.
  wrapper 검증은 gradle/actions/wrapper-validation(full SHA 핀)에 위임
- DeveloperExperienceContractTest 등의 CI YAML mutation 테스트:
  애플리케이션 test suite가 GitHub Actions YAML 파서를 검증하던 계층 역전
- 문서 drift 파서: verifyReadmeCommands, verifyRunbookReferences,
  verifyDocumentedLeafCount, verifyTestSourceSetRegistry
- 빈 레지스트리를 지키던 커스텀 YAML 파서: verifyTrivyignore,
  verifyQuarantineSunset, flaky-quarantine.yaml
- verifyConfigurationPropertiesProcessor, verifyOneTypePerFile:
  각각 ca.spring-config convention과 Checkstyle OneTopLevelClass가 대체
- 정상 입력으로도 성공할 수 없던 messaging always-fail task
- ModuleRegistry의 JSON 필드 집합 정확 일치, sample-portfolio negative guard

이동
- java/quality/spring 공통 설정을 configure(subprojects) 블록에서
  ca.java-conventions / ca.quality-conventions / ca.java-library /
  ca.spring-library convention plugin으로
- 아키텍처 검증을 ca.architecture로, JPA·messaging qualification을
  gradle/qualification/ 아래로, verifyEnvKeys를 :app-bootstrap 소유로

완화
- Git revision은 releaseCheck·아카이브 생성에서만 요구. 일반 빌드는 SNAPSHOT
- SpotBugs/FindSecBugs는 로컬 check에서 빼고 qualityCheck 레인으로

task 계층
- leaf check는 그 leaf만. architectureCheck / qualityCheck /
  configContractCheck / integrationCheck / ci / releaseCheck로 이름 분리

CI
- _reusable-gradle.yml 신규. checkout + wrapper validation + JDK/캐시 공통화
- fileserver-release.yml -> fileserver-certification.yml (CD가 아니라 certification)
- GitHub Actions = CI + artifact, Argo CD = CD 경계를 docs/ci-cd/boundary.md로 고정

순증감 +3,274 / -7,483.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 20:33:19 +09:00

142 lines
8.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CLAUDE.md
Repository guidance for the Java 21 + Spring Boot 4.0.8 Clean Architecture template.
## Prime Directive
Preserve architecture before optimizing for speed. The following eight HARD-STOP conditions are a
synchronized summary of the canonical local policy in `AGENTS.md`:
1. `domain-core` gains framework, transport, database, or cloud dependencies.
2. A controller directly uses a repository, Spring Data interface, or persistence entity.
3. An inbound DTO leaks into `application-core` or `domain-core`.
4. Business rules move into mappers, filters, configuration, settings, or controllers.
5. Project dependencies violate `src/config/architecture/modules.json` or the Gradle dependency
gate.
6. Completion is claimed without the relevant verification or a named reason it could not run.
7. A repository/corpus conclusion is made without evidence proportional to its scope and risk.
8. Non-trivial work closes without the required LLM Wiki capture or a reported capture block.
If this summary drifts from `AGENTS.md`, `AGENTS.md` wins and this summary must be resynchronized.
## Gradle policy authorities
- `src/config/architecture/modules.json`: every registered leaf identity, repository-relative source
paths, Gradle paths, allowed production project dependency edges, and the exact runtime
memberships of both composition roots. The registry owns the leaf list and its size; no document
restates the count, because a number written in prose drifts the moment a leaf is added.
- `src/settings.gradle`: fail-closed registry validation, project inclusion, and directory mapping.
- `src/build.gradle`: `verifyCleanArchitectureDependencies` and the other architecture-wide
verification tasks.
Commit policy is `human-only`: agents do not stage, commit, amend, or push implementation changes.
## Proportional workflow
- Low risk: work in the owning leaf, follow its nearest guidance, and run the focused check.
- Medium risk: use the relevant Superpowers design, planning, TDD, debugging, and review workflows
in proportion to the affected boundaries.
- High risk: make architecture and behavior decisions explicit, use staged architecture/spec/quality
review, and run architecture-wide verification authorized by the task.
Risk comes from change surface and runtime, security, data, or public-contract impact, not file
count.
## Module families
`src/config/architecture/modules.json` owns the complete leaf list. Root guidance summarizes
families; the nearest `src/**/CLAUDE.md` owns local rules. No task enforces this any more:
`verifyDocumentedLeafCount` was deleted along with the other documentation-drift parsers. A stated
count that disagrees with the registry is a defect, not a build failure — so do not state one.
| Family | Responsibility | Stable dependency direction |
| --- | --- | --- |
| `domain-core` | Pure domain model, invariants, events, ports | Java stdlib and registered value-only contracts |
| `application-core` | Commands, use cases, application policies, transaction ports | `domain-core`, `shared-contract` |
| `adapter:inbound:*` | HTTP, gRPC, GraphQL, WebSocket transport boundaries | application/domain/shared contracts |
| `adapter:outbound:persistence-*` | JPA/PostgreSQL and MongoDB persistence adapters | application/domain/shared contracts as registered |
| `adapter:outbound:*` | support, messaging, cache, notification, storage, file, HTTP client, identifier capabilities | application/domain/shared and registered support edge |
| `shared-contract` | Skeleton-wide operational contracts | Java stdlib only |
| `messaging:*` | Vendored messaging platform: a product with its own API, SPI, adapters and composition boundary, not a layer of this application | `messaging:*` only — it depends on no `domain-core`, `application-core`, or `shared-contract` type |
| `sample-portfolio` | Fixture/reference consumer | registered runtime leaves; never a production dependency |
| `app-bootstrap` | Spring Boot entrypoint and composition root | registered runtime leaves |
The `messaging:*` family is the one entry that is not a Clean Architecture layer, and it is listed so
that the exception is stated rather than inferred from a directory. It is a vendored library — its
own `*-api` leaves are its ports, its broker leaves are its adapters, its starter is its composition
root — and the messaging module review (`docs/reviews/2026-08-14-messaging-module-code-review.md`
MSG-023 §6.2) chose that layout deliberately over folding it into `adapter:outbound:*`. This
application is supposed to reach it the way it reaches any library: through an application-owned port
satisfied by an anti-corruption bridge in `adapter:outbound:messaging`. That bridge does not exist
yet (MSG-015), so today the composition root wires the starter directly; `src/messaging/CLAUDE.md`
holds the detail.
Never infer an individual leaf's Gradle path, allowed dependency, or test command from this table.
Read its `gradle_path`, `allowed_dependencies`, and `runtime_memberships` from
`src/config/architecture/modules.json`; derive the focused test from that Gradle path.
## Layer workflow
For a full use case, work in this order:
```text
domain-core
-> application-core
-> adapter:outbound:* (or persistence/identifier)
-> adapter:inbound:*
-> app-bootstrap wiring
```
Layer-only work stays inside that registered leaf plus its tests. If a required fix crosses a layer
or writable scope, stop and request context rather than expanding silently.
## Testing
- `domain-core`: pure JUnit unit tests.
- `application-core`: use-case tests with hand-rolled fakes; no web or persistence context.
- inbound adapters: focused transport slice/contract tests.
- persistence adapters: mapping/port contract tests; use a real datastore only when vendor semantics
require it.
- other outbound adapters: port contract tests with fake external systems; no real network.
- identifier: pure deterministic unit tests.
- bootstrap/settings: binding, validation, wiring, and architecture tests.
From `src/`, read the owning leaf's `gradle_path` from
`config/architecture/modules.json` and run `./gradlew <gradle-path>:test --console=plain`.
Architecture-wide commands:
```bash
./gradlew architectureCheck --console=plain
./gradlew :app-bootstrap:test --tests 'dev.caskeleton.bootstrap.architecture.*' --console=plain
./gradlew verifyPublicPathSnapshot --console=plain
./gradlew :app-bootstrap:verifyEnvKeys --console=plain
```
A leaf's `check` covers that leaf only — compile, its tests, Spotless, Checkstyle, Error Prone.
Repository-wide questions have their own names: `architectureCheck` (dependency direction, runtime
membership, application-core purity, Git-carryable sources), `qualityCheck` (SpotBugs, FindSecBugs),
`configContractCheck` (the environment contract), `integrationCheck` (the declared strict test
lanes). `ci` is check + architectureCheck + qualityCheck + configContractCheck; `releaseCheck` adds
provenance, archive hygiene and the public-path snapshot.
Use public-path and env-key checks only when their surfaces changed. Full `test`, `check` or `ci`
requires the controller's workflow authorization.
## Advisory and reporting
Use dependency-DAG/topological reasoning and 35 materially distinct alternatives when that many
exist; use fewer when the option set is smaller. Judgment findings include falsifiable assumptions
and counterarguments. Deterministic compile, dependency, secret, or failed-test findings use
Rule → Evidence → Fix without manufactured debate.
Citation verification is profile-based: none for `review-lite`, blocking citations for
`review-standard`, and all material citations for `audit-deep`/`regulated`. Durable reports are
triggered by high risk, at least 3 blocking findings, an architecture decision, explicit user request,
or the regulated profile. Otherwise a concise result is allowed.
## LLM Wiki capture
For non-trivial implementation or workflow changes, use the exact vault path and capture sequence in
`AGENTS.md`. If the controller explicitly excludes wiki writes for a dispatched task, report the
handoff instead of writing outside scope.