238 lines
13 KiB
Markdown
238 lines
13 KiB
Markdown
# 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 1–4.
|
||
- [ ] 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.
|