diff --git a/.planning/phases/32.1-mcp-oauth-for-plugin-apps-declared-scopes-mcp-subject-on-con/32.1-VALIDATION.md b/.planning/phases/32.1-mcp-oauth-for-plugin-apps-declared-scopes-mcp-subject-on-con/32.1-VALIDATION.md new file mode 100644 index 00000000..bb1d7459 --- /dev/null +++ b/.planning/phases/32.1-mcp-oauth-for-plugin-apps-declared-scopes-mcp-subject-on-con/32.1-VALIDATION.md @@ -0,0 +1,92 @@ +--- +phase: "32.1" +slug: "mcp-oauth-for-plugin-apps-declared-scopes-mcp-subject-on-con" +# 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 +nyquist_compliant: false +wave_0_complete: false +created: "2026-10-28" +--- + +# Phase 32.1 — Validation Strategy + +> Per-phase validation contract for feedback sampling during execution. +> Seeded from `32.1-RESEARCH.md` § Validation Architecture. No REQ-IDs are mapped; rows use success criteria SC-1..SC-4. + +--- + +## Test Infrastructure + +| Property | Value | +|----------|-------| +| **Framework** | Go `testing` (stdlib). Plugins use testcontainers-go v0.44.0 off `-short`. vue-oauth-layer uses `node --test`. | +| **Config file** | none — Go has no repo-level test config. Layer: `package.json` script `test`, copied from vue-menu-layer. | +| **Quick run command** | `go test -short ./modules/pact ./modules/pier ./modules/wristband ./modules/bouncer` | +| **Full suite command** | `go test -short ./...` in this repo; `go test ./...` in each plugin repo (Docker); `pnpm test` in vue-oauth-layer | +| **Estimated runtime** | ~60 seconds for the quick command; plugin non-short tests depend on Docker | + +--- + +## Sampling Rate + +- **After every task commit:** `go test -short` on the packages that commit touched (`./modules/pact`, `./modules/pier`, `./modules/wristband`, or the plugin's `-short` suite), plus `go vet` on those packages. +- **After every plan wave:** `go test -short ./...` in the repo that merged. Plugin waves that touch consent or revoke also run the non-short tests named below when Docker is up. +- **Before `$msd-verify-work`:** Full `-short` suite in the framework repo, non-short consent/revoke/backfill tests in sm-oauthserver-plugin, `go test -short ./...` in sm-user-plugin on the v0.1.14 branch, `pnpm test` in the layer, `go test ./cmd/summer -run TestDocsTree`. +- **Max feedback latency:** 120 seconds + +--- + +## Per-Task Verification Map + +| Task ID | Plan | Wave | Requirement | Threat Ref | Secure Behavior | Test Type | Automated Command | File Exists | Status | +|---------|------|------|-------------|------------|-----------------|-----------|-------------------|-------------|--------| +| 32.1-01-01 | 01 | 1 | SC-1 | — | Declared scope names are advertised and unknown names are rejected; OIDC discovery scopes stay unchanged | unit | `go test -short ./modules/wristband -run 'TestMCPScopes\|TestMetadata' -count=1` | ❌ W0 | ⬜ pending | +| 32.1-02-01 | 02 | 2 | SC-1 | — | `Implies` applies only to OAuth MCP subjects; personal tokens are not expanded | unit | `go test -short . -run 'TestMCP' -count=1` in sm-user-plugin on v0.1.14 | ❌ W0 | ⬜ pending | +| 32.1-01-02 | 01 | 1 | SC-1 | — | pier PRM `scopes_supported` matches the published catalog | unit | `go test -short ./modules/pier -run 'TestPRM\|TestProtected' -count=1` | ❌ W0 | ⬜ pending | +| 32.1-01-03 | 01 | 1 | SC-2 | — | `MCPCallFrom` returns the call subject on a dispatched tool and is empty on a plain request | unit | `go test -short ./modules/pier -run TestDispatch -count=1` | ❌ W0 | ⬜ pending | +| 32.1-03-01 | 03 | 3 | SC-3 | — | Consent replace, revoke of one client, and MCP code deletion do not touch another client | integration | `cd ../sm-oauthserver-plugin && go test -count=1 -run 'TestMCPConsent\|TestAuthorizations\|TestMCPRevocation'` | ❌ W0 | ⬜ pending | +| 32.1-04-01 | 04 | 4 | SC-3 | — | Consent page posts scopes as JSON and does not render phrasebook strings as HTML | unit | `pnpm test` in vue-oauth-layer | ❌ W0 | ⬜ pending | +| 32.1-05-01 | 05 | 5 | SC-4 | — | Docs identifiers resolve | unit | `go test ./cmd/summer -run TestDocsTree -count=1` | ✅ | ⬜ pending | + +*Status: ⬜ pending · ✅ green · ❌ red · ⚠️ flaky* + +Task IDs above are placeholders until plans exist. The executor updates this map to the real task IDs. + +--- + +## Wave 0 Requirements + +- [ ] `modules/pact` test that `FrontendTokenScope` still composites without `Implies` and that `MCPCallFrom` is false on a bare context — SC-2 negative +- [ ] `modules/pier` PRM test with and without `MCPAdvertisedScopes` — SC-1 +- [ ] `modules/pier` dispatch test that the context carries `MCPCall` for a frontend tool and a backend tool — SC-2 +- [ ] sm-user-plugin `mcp_guard_test.go` cases for `Implies`, written against v0.1.14 — SC-1 +- [ ] sm-oauthserver-plugin consent upsert, replace-not-merge, offline_access flag, revoke-deletes-MCP-code, backfill idempotence — SC-3 +- [ ] `authorizations_smoke_test.go` key list includes `kind` — SC-3 +- [ ] vue-oauth-layer `tests/connect.test.ts` — page mapping +- [ ] Framework install: none. Layer: `pnpm install` in the new repo once `package.json` exists + +Existing wristband and pier test infrastructure hosts the new cases. No new test dependency. + +--- + +## Manual-Only Verifications + +| Behavior | Requirement | Why Manual | Test Instructions | +|----------|-------------|------------|-------------------| +| Patch tags of the framework and `sm-oauthserver-plugin`, and the changelog post | SC-4 | Tagging and publishing need an explicit user go-ahead and are not plan steps | After the code lands, ask before `git tag` or `scripts/changelog-post.py publish` | + +All other phase behaviors have automated verification. + +--- + +## Validation Sign-Off + +- [ ] All tasks have `` verify or Wave 0 dependencies +- [ ] Sampling continuity: no 3 consecutive tasks without automated verify +- [ ] Wave 0 covers all MISSING references +- [ ] No watch-mode flags +- [ ] Feedback latency < 120s +- [ ] `nyquist_compliant: true` set in frontmatter + +**Approval:** pending