Files
clean-architecture-backend-…/docs/superpowers/plans/2026-08-15-wave6-final-qualification.md
T

238 lines
13 KiB
Markdown
Raw 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.
# Wave 6 — Final Qualification and Documentation Sync Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans (this wave is
> verification-heavy and benefits from one session holding the whole evidence set).
> **Read [`2026-08-15-five-adapter-runtime-remediation-index.md`](2026-08-15-five-adapter-runtime-remediation-index.md)
> first.**
> **Entry criterion:** Wave 5 complete — build logic extracted with a clean baseline diff.
**Goal:** Run every blocking gate, the full activation matrix, and every environment smoke; reconcile
generated metadata and documentation with the code; and produce the evidence set that lets each
Definition-of-Done checkbox in spec §13 be ticked with a command and its output attached.
**Architecture:** Wave 6 adds no capability. It executes, records, and reconciles. Every claim is
backed by a command and its output stored under
`docs/superpowers/plans/evidence/2026-08-15-wave6-final/`. A checkbox without attached evidence stays
unticked, and a gate that could not run is reported as not-run with its reason — never as passing.
**Spec:** [`2026-08-15-five-adapter-runtime-remediation-review-design.md`](../specs/2026-08-15-five-adapter-runtime-remediation-review-design.md)
(§12 in full, §13, §11 Wave 6)
---
## Global Constraints
Inherited from the index. Wave 6 adds:
- **Use `superpowers:verification-before-completion` before any completion claim.** Evidence precedes
assertion, always.
- **A not-run gate is reported as not-run.** Spec HARD-STOP 6 (`AGENTS.md:22`) makes claiming
completion without the verification, or without naming why it could not run, a stop condition.
- **No conclusion broader than its evidence** (HARD-STOP 7). "The matrix passed" requires the matrix,
not a representative lane.
- **The wave ends with the LLM Wiki capture** required by `AGENTS.md:79-90`, or with an explicit
reported reason it was blocked.
---
## Task 1: Build and architecture gates
- [ ] Run and capture each:
```bash
cd src
./gradlew clean compileJava compileTestJava --warning-mode=fail --no-daemon --console=plain
./gradlew test --warning-mode=fail --no-daemon --console=plain
./gradlew check --warning-mode=fail --no-daemon --console=plain
./gradlew verifyCleanArchitectureDependencies verifyEnvKeys \
verifyRuntimeModuleMembership verifyPublicPathSnapshot \
verifyDocumentedLeafCount --console=plain
```
- [ ] Confirm `./gradlew wave0RedReport --console=plain --no-daemon` reports an **empty** red set,
then delete the `wave0Red` lanes and the aggregate — the characterizations they tracked are now
ordinary tests, and a permanent lane for an empty set is a lane that stops being read.
## Task 2: Focused module gates
Gradle paths are read from `src/config/architecture/modules.json`, never from memory.
- [ ] Run and capture:
```bash
cd src
./gradlew :adapter:outbound:persistence-jpa:test --console=plain
./gradlew :adapter:outbound:persistence-mongo:test --console=plain
./gradlew :adapter:outbound:messaging:test --console=plain
./gradlew :adapter:outbound:notification:test --console=plain
./gradlew :adapter:inbound:graphql:test --console=plain
./gradlew :adapter:inbound:graphql:graphqlStableTest \
:app-bootstrap:graphqlRuntimeQualification \
conditionalTransportQualification --console=plain
```
- [ ] Run the messaging platform's Stable facade focused tests and its live-broker lane separately.
Record explicitly that ordinary `test` does **not** substitute for the Docker-backed
qualification.
- [ ] Persistence blocking lanes:
```bash
cd src
./gradlew :adapter:outbound:persistence-jpa:jpaPlatformReleaseGate -Pjpa.matrix.versions=16 --console=plain
./gradlew :adapter:outbound:persistence-jpa:jpaPlatformReleaseGate -Pjpa.matrix.versions=17 --console=plain
./gradlew :adapter:outbound:persistence-jpa:jpaPlatformReleaseGate -Pjpa.matrix.versions=18 --console=plain
./gradlew :adapter:outbound:persistence-mongo:mongoStableContractTest \
:adapter:outbound:persistence-mongo:mongoReplicaSetTest \
:adapter:outbound:persistence-mongo:mongoFailoverTest \
:adapter:outbound:persistence-mongo:mongoMigrationTest \
:adapter:outbound:persistence-mongo:mongoCompatibilityTest \
:adapter:outbound:persistence-mongo:mongoSecurityIntegrationTest \
:adapter:outbound:persistence-mongo:mongoPerformanceTest --console=plain
```
- [ ] Confirm Wave 2 Task B5's decision is reflected: either the three lanes exist and run, or their
Stable blocking claim is gone from `src/config/mongodb/release-contracts.json`,
`docs/mongodb/advanced/sharding.md`, and `scripts/verify-mongodb-advanced.sh`. Attach the
`ReleaseManifestTaskExistenceTest` result.
## Task 3: The activation matrix
Run each row and capture the resolved activation report, health, exit code, WARN/ERROR count, and the
bean/thread inventory.
| # | Matrix | Expected |
| --- | --- | --- |
| 1 | five off | boots with no external infrastructure; health OK; adapter beans, resources, threads, endpoints all zero |
| 2 | JPA only | PostgreSQL + Flyway + Hibernate `validate` succeed; no Mongo, GraphQL, broker, or provider |
| 3 | Mongo only | replica set, client, topology, security succeed; no JPA entity, repository, or pool |
| 4 | Messaging only | broker publish/consume succeeds; with relay off, no database needed |
| 5 | Notification + JPA, `INGEST_ONLY` | durable accept on a frozen non-empty versioned route; provider credentials, calls, and workers all zero; after a `SERVING` restart, exactly one delivery on the same route |
| 6 | Notification + JPA, `SERVING` | reference provider delivery and receipt succeed |
| 7 | GraphQL only | schema endpoint plus security/policy pipeline succeed; no persistence resolver |
| 8 | relay on, dependency missing | startup rejects, **naming the exact missing switch or provider** |
| 9 | JPA + Mongo | distinct ports succeed; two implementations of one port is a startup rejection, not a `@Primary` pick |
| 10 | five on | every dependency and endpoint ready; no silent fallback and no duplicate authority |
- [ ] Row 8 must be checked for the *name*, not merely for a failure. A generic "misconfiguration" is a
fail.
- [ ] Row 9's conflict case must fail; a bean-ordering or `@Primary` resolution is a fail.
## Task 4: Environment and runtime gates
- [ ] Compose artifacts, statically then dynamically:
```bash
./scripts/verify-compose-profile-contracts.sh
./scripts/run-compose-runtime-smoke.sh --matrix src/config/runtime/compose-profile-contracts.json
```
- [ ] Confirm the matrix owned every lane: `off-local`, `off-dev`, `off-prod`, each local adapter lane,
`shared-infra-local`, `shared-infra-dev`, `prod-smoke`, `all-adapters`.
- [ ] Confirm `prod-smoke` actually **started** TLS PostgreSQL, the app, Keycloak, and MinIO and ran
both one-shots — a `config`-only pass is a fail.
- [ ] Confirm each run stored exit code, active profile, resolved activation report, and WARN/ERROR
count as artifacts.
- [ ] Confirm no dev or prod lane was made to pass with a local override. Spec §12.4 does not accept
that as evidence for the profile.
- [ ] Confirm teardown left no stray project or volume: `docker ps -a`, `docker volume ls`.
## Task 5: Documentation and metadata reconciliation
- [ ] Regenerate Spring configuration metadata and diff against the env registry and the YAMLs; any
drift is a fail.
- [ ] Confirm every registry env key appears in `src/.env.example` and that no example carries a real
secret.
- [ ] Confirm `docs/registries/env-keys.yaml` lists the five masters with `false` defaults and the two
subordinate selectors with their `required-when` conditions.
- [ ] Confirm no demoted key (`APP_MESSAGING_BROKER`, `APP_NOTIFICATION_SLACK_PROVIDER`,
`APP_NOTIFICATION_EMAIL_PROVIDER`, `app.jpa-platform.enabled`) is documented anywhere as an
activation switch.
- [ ] Update `README.md` with the five switches, the Compose minimum version, and the two script entry
points.
- [ ] Update `src/app-bootstrap/CLAUDE.md`, replacing its "19-leaf dependency list" phrasing with a
pointer to the registry — a count in prose is the drift `AGENTS.md:52-55` forbids.
- [ ] Confirm the capability docs do not label as Stable anything the index's scope boundaries exclude:
Mongo reactive, change streams, sharding, Atlas, KMS; Notification before NTF-INT-007 is closed.
## Task 6: Definition of Done
Walk spec §13 and tick each box **only** with attached evidence. Reproduced here as the checklist:
- [ ] Five runtime facades on one bootJar runtime classpath.
- [ ] Five canonical master switches in registry, YAML, metadata, and docs, all defaulting `false`.
- [ ] All-off `local`, `dev`, `prod` smoke succeeds with no external resources.
- [ ] Each adapter's off invariant and on fail-closed contract pinned by full-context tests.
- [ ] Mongo, GraphQL, and Messaging Stable facades' resolved runtime membership matches the registry.
- [ ] The JPA switch controls the whole DataSource/Hikari/entity/repository/Hibernate/Flyway/DB
health-and-metrics graph.
- [ ] Messaging has a real broker bridge and a consistent relay dependency.
- [ ] Notification `SERVING` works through production assemblers; `INGEST_ONLY` starts no worker.
- [ ] Notification handoff proves, in one project and DB volume, `INGEST_ONLY` accept → restart →
`SERVING` delivery exactly once on the same frozen route, with zero duplicates.
- [ ] GraphQL policy and JWT context execute on the real `/graphql` request path.
- [ ] GraphQL blocking qualification runs the bootJar JWT composition exactly once and uses neither
class-existence nor test-only Basic Auth as release evidence.
- [ ] `SPRING_PROFILES_ACTIVE` is exactly one of `local|dev|prod`; profileless, multiple, and unknown
deployments are rejected.
- [ ] GraphQL on requires one environment-permitted `APP_GRAPHQL_DEPLOYMENT_MODE`; the legacy
boolean/enum split-brain is rejected.
- [ ] Profiles and env example/secret sources are separated; real secret files are excluded from
tracking, rendering, and evidence.
- [ ] Compose minimum version, per-profile exact service sets, the whole merged model, and mount-target
uniqueness are verified by the canonical script.
- [ ] The runtime-smoke wrapper performs create, `up --wait`, required one-shots, sanitized evidence,
and unique-project teardown with zero skips across `local`, `dev`, and `prod` blocking lanes.
- [ ] PostgreSQL, Mongo, broker, MinIO, and Keycloak/realm smoke evidence exists.
- [ ] The Keycloak realm provides a client-credentials-only service account, audience, and role claims,
and real JWT-protected REST and GraphQL requests succeed against the same issuer URL per lane.
- [ ] Full `test` and `check`, plus architecture, env, public-path, and strict qualification, all pass.
- [ ] Zero Gradle, javac, Checkstyle, SpotBugs, and runtime-startup errors and warnings; zero allowlist
entries; IDE Problems zero confirmed separately on the same toolchain.
- [ ] The real active profile and the structured-log profile field agree; zero late-MeterFilter
warnings.
- [ ] After convention-plugin extraction, task selection, dependency graph, and evidence semantics are
unchanged.
- [ ] Every P0 blocker on a runtime path from the detailed module reviews is either closed or its
capability is explicitly inactive/experimental.
- [ ] Changed files, commands, results, not-run/blocked items, and evidence grades are captured in the
LLM Wiki branch-note.
## Task 7: LLM Wiki capture
Per `AGENTS.md:79-90`:
- [ ] Create or update
`/home/donghyeon/workspace/ai-tool/llm-wiki-private/raw/branch-notes/<branch-name>.md` with the
implementation, changed files, decisions, verification commands, failures/blocks, and evidence
grades.
- [ ] Create derived documents where genuine material exists: `raw/errors/`, `raw/interviews/`,
`raw/blog-topics/`. Each links upward via `## Parent`; the branch-note's `## Cluster / 묶음`
links back.
- [ ] Where no derived document is warranted, record that judgement explicitly ("추출할 별도 글감
없음") rather than omitting the section.
- [ ] Do not create `wiki/blog/`, `wiki/interview/`, `wiki/portfolio/`, `wiki/concepts/`, or
`wiki/projects/` without an explicit canonical extraction request.
## Task 8: Final report
Per `AGENTS.md:239-251`, the closing response states: changed files; the core changes; verification
commands run; verifications that failed or could not run, with reasons; the Wiki capture result; and
remaining risks or follow-ups.
- [ ] Explicitly restate what remains **out of scope and not production-ready**, from the index's scope
boundaries: Mongo reactive, change streams, sharding, Atlas, KMS; Notification's at-rest decision
if the threat-model branch was chosen; object storage's runtime inclusion; Fileserver internals.
---
## Wave 6 Exit Criteria
- [ ] Every §13 checkbox above is ticked **with attached evidence**, or is explicitly reported as
not-met with its reason.
- [ ] `docs/superpowers/plans/evidence/2026-08-15-wave6-final/` holds the output of every command in
Tasks 14.
- [ ] The LLM Wiki branch-note exists and links its derived documents.
- [ ] No completion, "all passing", or "production-ready" claim appears anywhere without the command
output that supports it.