diff --git a/.planning/phases/19.7-generic-mcp-module/19.7-VALIDATION.md b/.planning/phases/19.7-generic-mcp-module/19.7-VALIDATION.md index f576f404..a94109ea 100644 --- a/.planning/phases/19.7-generic-mcp-module/19.7-VALIDATION.md +++ b/.planning/phases/19.7-generic-mcp-module/19.7-VALIDATION.md @@ -3,7 +3,7 @@ phase: "19.7" slug: "generic-mcp-module" # status lifecycle: draft (seeded by plan-phase) → validated (set by validate-phase §6) # audit-milestone §5.5 distinguishes NOT-VALIDATED (draft) from PARTIAL (validated + nyquist_compliant: false) (#2117) -status: draft +status: validated nyquist_compliant: true wave_0_complete: true created: "2026-10-21" @@ -94,8 +94,23 @@ Filled in by the planner per task; the behaviour → test map is: | C-WR-01 | `readLinkCode` and `isLinkCode` | vitest | `pnpm --dir ../sm-demo-app/vue-demo-app run test` (`app/lib/linkCode.test.ts` required by the gate) | ✅ `sm-demo-app/vue-demo-app/app/lib/linkCode.test.ts` | ✅ green | | T-19.7-64 (P-40) | workspace check, consumers built against the unreleased user plugin, unreleased-pin policy and `PHASE197_RELEASED` strict mode | gate | `bash scripts/check-phase19.7.sh --self-test`, `--plugins`, `--consumers`; `PHASE197_RELEASED=1 bash scripts/check-phase19.7.sh --consumers` exits 1 before the release | ✅ `scripts/check-phase19.7.sh` | ✅ green | | A-IN-02 | cooler's `KeyPrefix` and `keyPrefix` carry their own doc comments | docs | `bash scripts/check-phase19.7.sh --docs` | ✅ `scripts/check-phase19.7.sh` | ✅ green | +| RA-WR-01 | fan-out never waits on a session lock under the router lock; re-filter guard checks bounded by `mcp.call_timeout` | integration | `go test -short -race ./modules/pier -run '^TestLockScopeUnderWidening$'` | ✅ `modules/pier/lock_scope_test.go` | ✅ green | +| RA-WR-02 | the stateless fingerprint ignores the OAuth token id; a narrow token does not flip a shared server's tool set mid-call | unit + integration | `go test -short ./modules/pier -run '^(TestFingerprintIgnoresTokenID\|TestStatelessSharedBinding)$'` | ✅ `modules/pier/fingerprint_test.go`, `modules/pier/stateless_fanout_test.go` | ✅ green | +| RA-WR-03 | a guard error while widening or recomputing (stateless, stateful, on an event) does not narrow the session | integration | `go test -short ./modules/pier -run '^TestWideningGuardError$'` | ✅ `modules/pier/widening_test.go` | ✅ green | +| RA-WR-04 | LRU eviction spares a server with a listen stream; a revocation still ends the stream | integration | `go test -short ./modules/pier -run '^TestStatelessFanOut$'` | ✅ `modules/pier/stateless_fanout_test.go` | ✅ green | +| RA-WR-05 | prompt Render errors stay out of the client's answer (stateful and stateless) | integration | `go test -short ./modules/pier -run '^TestPromptRenderError$'` | ✅ `modules/pier/prompt_ceiling_test.go` | ✅ green | +| RA-IN-02 | stream bearer re-checks carry the client address | integration | `go test -short ./modules/pier -run '^TestStreamRecheckClientIP$'` | ✅ `modules/pier/token_events_test.go` | ✅ green | +| RA-IN-04 | the non-reserving fallback writes the record before building the server; a failed initialize deletes it (Count-then-Put race deferred) | integration | `go test -short ./modules/pier -run '^TestSessionReserve$'` | ✅ `modules/pier/reserve_test.go` | ✅ green | +| RA-IN-05 | an admin personal token whose scopes all resolve to nothing gets "the token's scopes no longer grant this route", not "account unknown"; the listing check is a refusal; known scope, missing admin and OAuth subject unchanged | Postgres | `go test ./modules/pier -run '^TestBackendScopeUnavailable$'` | ✅ `modules/pier/backend_scope_unavailable_test.go` | ✅ green | +| RA-WR-06/RA-IN-06 | the verdict is qualified while demo pins are unreleased; a silent failing pin check is refused | gate | `bash scripts/check-phase19.7.sh --self-test` (`pins-test-only-unrecorded`, `pins-silent-failure`) | ✅ `scripts/check-phase19.7.sh` | ✅ green | +| RB-WR-01/RB-IN-01 | Ctrl+S and Ctrl+Enter commit a draft inside an open or closed field-type shadow root; control-character and bare `https://` URLs render no link and open no window | vitest | `npm --prefix admin run test` | ✅ `admin/tests/app/hotkeysEditing.test.ts`, `admin/tests/account/AccountContributions.test.ts` | ✅ green | +| RB-WR-02 | a padded or whitespace-carrying token scope name fails boot | unit | `go test -short ./modules/cabana -run '^TestTokenScopeNameParity$'` | ✅ `modules/cabana/token_scope_name_test.go` | ✅ green | +| RB-IN-02 | a failing Applies marks its My account section | unit | `go test -short ./modules/cabana -run '^TestAccountContributionsAppliesFailureFlagsSection$'` | ✅ `modules/cabana/account_contributions_hardening_test.go` | ✅ green | +| RC-WR-01 | a backend grant acts only as the administrator it was consented for: decide 409 matrix, binding through code, exchange, rotation and verifier, link change, revoke racing a rotation | Postgres + integration + e2e | oauthserver plugin `go test . -run '^TestMCPBackendBinding$'`; `go test -short ./modules/pier -run '^(TestToolsList\|TestFanOut)$'`; demo `TestMCPEndToEnd` | ✅ `sm-oauthserver-plugin`, `modules/pier/tools_list_test.go`, `modules/pier/fanout_test.go`, `sm-demo-app/mcp_e2e_test.go` | ✅ green | +| RC-CR-01/RC-WR-02 | a self-service password change revokes grants rotated after the session's iat and keeps the session; a ban alone refuses the verifier and rotation | Postgres | user plugin `GOWORK=off go test . -run '^TestAccessRevocation$'`; oauthserver plugin `go test . -run '^(TestMCPGrantRevocation\|TestMCPVerifierRevocation)$'` | ✅ `plugins/golem15/user/access_revocation_test.go`, `sm-oauthserver-plugin/mcp_revocation_test.go` | ✅ green | +| RC-IN-01/RC-IN-03 | a link code in the query string is ignored on POST; avatar and logo fallbacks use the public path | Postgres | user plugin `GOWORK=off go test . -run '^(TestBackendLinkShowPost\|TestAvatarURL\|TestOrganisationLogo)$'` | ✅ `plugins/golem15/user/backend_link_show_test.go`, `plugins/golem15/user/organisation_logo_test.go` | ✅ green | -*Status legend: ✅ green · ❌ red · ⚠️ flaky. Every row is green as of the plan 09 gate run (`bash scripts/check-phase19.7.sh --all`, every stage PASS). The rows after D-31 are the gap closure (plans 06-09).* +*Status legend: ✅ green · ❌ red · ⚠️ flaky. Every row is green as of the plan 09 gate run (`bash scripts/check-phase19.7.sh --all`, every stage PASS). The rows after D-31 are the gap closure (plans 06-09); the RA-/RB-/RC- rows are the re-review fixes (19.7-REREVIEW-FIX.md), added by the 2026-10-24 validation audit.* --- @@ -127,3 +142,15 @@ Filled in by the planner per task; the behaviour → test map is: - [x] Nyquist compliance recorded in the frontmatter **Approval:** plan 19.7-05 (the gate passes in full); extended by plan 19.7-09 for the gap closure (the gate passes in full) + +--- + +## Validation Audit 2026-10-24 + +The audit compared the map with the re-review fixes (19.7-REREVIEW-FIX.md). Fifteen behaviours had tests but no row, and they are now in the map. RA-IN-01, RA-IN-03, RB-IN-04 and RC-IN-02 changed only documentation, so they get no row. RA-IN-05 had no test, and `TestBackendScopeUnavailable` (49a3df6) now covers it. + +| Metric | Count | +|--------|-------| +| Gaps found | 1 | +| Resolved | 1 | +| Escalated | 0 |