docs(32.1-05): complete the unit tests and release plan

- Record the tag-and-publish decision, changelog notes, and roadmap check
- Leave the release decision file unchanged
This commit is contained in:
2026-10-28 16:44:14 +01:00
parent 9094bf9ad9
commit bba6539883
4 changed files with 307 additions and 2 deletions

View File

@@ -1621,7 +1621,7 @@ Plans:
**Goal:** As an application whose plugins declare their own member token scopes, I want an agent connected to `/mcp` over OAuth to get the same tools, attribution and revocation as one using a personal token, so that OAuth sign-in can be switched on in production. A consuming app's agent-access work found three gaps (its D-36, D-37 and D-38); all three are additive and ship as patch releases of the framework (0.5.x) and `sm-oauthserver-plugin`.
**Requirements**: TBD
**Depends on:** Phase 19.4 (OIDC provider on wristband), Phase 19.7 (generic MCP module)
**Plans:** 4/5 plans executed
**Plans:** 5/5 plans executed
**Success Criteria** (what must be TRUE):
1. Scopes a plugin declares through `pact.HasFrontendTokenScopes` can be requested, consented to and granted over MCP OAuth: the wristband metadata and authorize allow-list and pier's protected-resource scopes include them, so a tool route behind `user.scope:<declared>` lists and runs for an OAuth agent granted that scope. Today the list is fixed to `read`, `write`, `ai`, `offline_access` (and `backend`).
@@ -1643,7 +1643,7 @@ Plans:
- [x] 32.1-04-PLAN.md — vue-oauth-layer /connect checkboxes
**Wave 5** *(blocked on Wave 4 completion)*
- [ ] 32.1-05-PLAN.md — Unit tests, then the release checkpoint
- [x] 32.1-05-PLAN.md — Unit tests, then the release checkpoint
### Phase 33: SEO output, audit and content

View File

@@ -0,0 +1,206 @@
---
phase: 32.1-mcp-oauth-for-plugin-apps-declared-scopes-mcp-subject-on-con
plan: 05
subsystem: auth
tags: [mcp, oauth, release, changelog, scopes]
requires:
- phase: 32.1-01
provides: MCP scope list and MCPCall on the tool-call context
- phase: 32.1-02
provides: OAuth implied scopes in sm-user-plugin
- phase: 32.1-03
provides: MCP consent replace, kind, and backfill
- phase: 32.1-04
provides: vue-oauth-layer /connect
provides:
- "Unit tests for a bare MCP call, both guards, PRM scopes, implied scopes, consent replace, kind, and backfill"
- "SummerCMS v0.5.2, sm-user-plugin v0.1.16, sm-oauthserver-plugin v0.1.4, and local vue-oauth-layer v0.1.0"
- "Changelog post https://summercms.io/changelog/summercms-0-5-2"
affects: [33]
actuals:
tokens: 6474
tasks: 4
commits: 1
plan_head_before: 06a144e19f1bca9b918af7adfc44e7b7a1e3f011
plan_head_after: 9094bf9ad99c92b4343d8d3f1062ef4863f58e00
tech-stack:
added: []
patterns:
- "Patch tags are computed from git tag --list at release time, recorded in 32.1-05-release-decision.txt before any ref changes"
- "sm-oauthserver-plugin bumps require versions after those tags are pushed and keeps the summercms replace"
key-files:
created:
- .planning/phases/32.1-mcp-oauth-for-plugin-apps-declared-scopes-mcp-subject-on-con/32.1-05-release-decision.txt
- .planning/phases/32.1-mcp-oauth-for-plugin-apps-declared-scopes-mcp-subject-on-con/32.1-05-changelog-notes.md
- modules/pact/mcp_call_negative_test.go
- modules/pier/dispatch_mcpcall_test.go
- modules/pier/prm_scopes_test.go
- ../sm-user-plugin/mcp_implies_test.go
- ../sm-oauthserver-plugin/mcp_consent_test.go
- ../sm-oauthserver-plugin/authorizations_kind_test.go
- ../sm-oauthserver-plugin/mcp_backfill_test.go
modified:
- ../sm-oauthserver-plugin/go.mod
- ../sm-oauthserver-plugin/go.sum
- .planning/ROADMAP.md
key-decisions:
- "tag-and-publish. Framework v0.5.2 on master, sm-user-plugin v0.1.16 on phase-32.1-mcp-implied-scopes, sm-oauthserver-plugin v0.1.4 on master after the require bump, vue-oauth-layer v0.1.0 local only."
- "sm-user-plugin v0.1.16 stays on phase-32.1-mcp-implied-scopes and is not retargeted onto v0.1.15. That tag is not an ancestor."
- "vue-oauth-layer has no origin. The tag was not pushed and no remote was created."
patterns-established:
- "Release decision file is written from for-each-ref before the first tag or push and is not rewritten."
requirements-completed: []
coverage:
- id: D1
description: "A bare context has no MCP call, both guards record MCPCall, and PRM uses advertised scopes or falls back."
verification:
- kind: unit
ref: modules/pact/mcp_call_negative_test.go#TestMCPCallFromBareContext
status: pass
- kind: unit
ref: modules/pier/dispatch_mcpcall_test.go#TestDispatchMCPCallBothGuards
status: pass
- kind: unit
ref: modules/pier/prm_scopes_test.go#TestPRMUsesAdvertisedScopes
status: pass
human_judgment: false
- id: D2
description: "OAuth implied scopes do not expand a personal token, write does not grant read, and the subject slice is unchanged."
verification:
- kind: unit
ref: sm-user-plugin/mcp_implies_test.go#TestMCPImpliesPersonalUnchanged
status: pass
human_judgment: false
- id: D3
description: "MCP consent replace, offline_access, revoke, authorization kind, and idempotent backfill."
verification:
- kind: integration
ref: sm-oauthserver-plugin/mcp_consent_test.go#TestMCPConsentReplace
status: pass
- kind: integration
ref: sm-oauthserver-plugin/mcp_backfill_test.go#TestMCPConsentBackfillIdempotent
status: pass
human_judgment: false
- id: D4
description: "Patch tags pushed where origin existed, and the framework changelog post is live."
verification:
- kind: other
ref: python3 plan task-4 verify (exit 0) against 32.1-05-release-decision.txt and https://summercms.io/changelog/summercms-0-5-2
status: pass
human_judgment: false
duration: 34min
completed: 2026-10-28
status: complete
---
# Phase 32.1 Plan 05: Unit tests and patch release Summary
**SummerCMS v0.5.2, sm-user-plugin v0.1.16, sm-oauthserver-plugin v0.1.4, and local vue-oauth-layer v0.1.0 ship the MCP OAuth scope, caller, and consent gaps, with the framework changelog posted**
## Performance
- **Duration:** 34 min
- **Started:** 2026-10-28T15:09:30Z
- **Completed:** 2026-10-28T15:42:50Z
- **Tasks:** 4
- **Files modified:** 12
`actuals.tokens` is chars/4 of `git show` for `9094bf9`, `756797c`, `4f8618e`, and `a7743e7`, plus the decision file and changelog notes (25896 / 4). This summary is not in that count. `commits: 1` is `git rev-list --count 06a144e19f1bca9b918af7adfc44e7b7a1e3f011..9094bf9` at summary time. The metadata commit is after that range.
## Accomplishments
- Framework tests prove a bare context has no MCP call, both guards set one, and PRM uses an advertised list or falls back.
- sm-user-plugin tests keep implied scopes off the stored subject. sm-oauthserver-plugin tests prove consent replace, offline access, revoke, authorization kind, and an idempotent backfill.
- Tags: SummerCMS `v0.5.2` on `9094bf9` (pushed `master`, then the tag), sm-user-plugin `v0.1.16` on `756797c` (pushed `phase-32.1-mcp-implied-scopes`, then the tag), sm-oauthserver-plugin `v0.1.4` on `a7743e7` (pushed `master`, then the tag), vue-oauth-layer `v0.1.0` on `7f805b3` (local only).
- Changelog post id 46: https://summercms.io/changelog/summercms-0-5-2. The plan python verify exited 0.
- No app submodule pointer moved. `go.work` in sm-oauthserver-plugin stayed unstaged.
## Task Commits
The test commits were already on the branches before this continuation. They were not redone.
1. **Task 1: Tracer: bare context has no MCP call, and both guards' tool calls do** - `9094bf9` (test, summercms.go)
2. **Task 2: Plugin, layer, and docs proofs** - `756797c` (test, sm-user-plugin), `4f8618e` (test, sm-oauthserver-plugin). vue-oauth-layer had no new commit in this plan; its tests were already on `7f805b3`.
3. **Task 3: Release checkpoint** - no commit. The accepted option is `tag-and-publish`, recorded in `32.1-05-release-decision.txt` before any tag or push. That file was not rewritten.
4. **Task 4: Tag and publish** - `a7743e7` (chore, sm-oauthserver-plugin) sets `summercms v0.5.2` and `sm-user-plugin v0.1.16` and keeps the summercms replace. Tags and pushes are listed above. No framework commit in this task before the metadata commit.
**Plan metadata:** this summary, the decision file, the changelog notes, and the roadmap check, committed in summercms.go after this file was written.
## Files Created/Modified
- `modules/pact/mcp_call_negative_test.go` - bare context and a FrontendTokenScope literal without Implies
- `modules/pier/dispatch_mcpcall_test.go` - frontend and backend tool calls record MCPCall
- `modules/pier/prm_scopes_test.go` - advertised scopes and the PRMScopes fallback
- `../sm-user-plugin/mcp_implies_test.go` - personal token, write-does-not-grant-read, subject slice unchanged
- `../sm-oauthserver-plugin/mcp_consent_test.go` - replace, offline access, revoke
- `../sm-oauthserver-plugin/authorizations_kind_test.go` - kind mcp or oidc
- `../sm-oauthserver-plugin/mcp_backfill_test.go` - idempotent backfill
- `../sm-oauthserver-plugin/go.mod` - require SummerCMS v0.5.2 and sm-user-plugin v0.1.16
- `../sm-oauthserver-plugin/go.sum` - sum for sm-user-plugin v0.1.16
- `.planning/phases/32.1-mcp-oauth-for-plugin-apps-declared-scopes-mcp-subject-on-con/32.1-05-release-decision.txt` - checkpoint record and the tag lists from before the release
- `.planning/phases/32.1-mcp-oauth-for-plugin-apps-declared-scopes-mcp-subject-on-con/32.1-05-changelog-notes.md` - notes published for v0.5.2
- `.planning/ROADMAP.md` - 32.1-05 checked, 5/5 plans executed
## Decisions Made
- The checkpoint option `tag-and-publish` was applied. Versions came from the tag lists in the decision file: next v0.5 patch is v0.5.2, next user v0.1 patch is v0.1.16, next oauth v0.1 patch is v0.1.4, and vue-oauth-layer is v0.1.0 because that tag did not exist.
- sm-user-plugin was tagged on `phase-32.1-mcp-implied-scopes` at `756797c`. `v0.1.15` is not an ancestor. The tag was not moved onto `v0.1.15`. The tag message and the changelog say the missing-scope fields from v0.1.15 are absent. The plugin `go.mod` still requires SummerCMS v0.5.0; the new seams are in v0.5.2, which sm-oauthserver-plugin v0.1.4 requires.
- vue-oauth-layer has no `origin`. `v0.1.0` is local. `git@git.golem15.com:golem15/vue-oauth-layer.git` was not created.
- STATE.md and state.json were not edited and are not in the metadata commit. Current Position stays phase 33.
## Deviations from Plan
### Auto-fixed Issues
None during the release continuation. The test tasks were already committed.
The user-plugin test file is `mcp_implies_test.go` at the plugin root, not `classes/mcp_guard_test.go`. That path was chosen by the earlier test commit and was left as committed.
---
**Total deviations:** 0 auto-fixed during the release continuation
**Impact on plan:** The release followed the accepted checkpoint. The user-plugin tag is intentionally not based on v0.1.15.
## Issues Encountered
- Pushing summercms.go `master` published 44 commits since v0.5.1, including the phase 32 review fixes and planning commits that were already on local master. The push was a fast-forward. No force-push.
- Phase 33 plan 01 reserved the name v0.5.2 for a later tag that would also carry phase 33 seams, and plan 33-14 was going to create that tag. This release took v0.5.2 because it was the next v0.5 patch. Phase 33 must not reuse v0.5.2. The next framework patch is v0.5.3 unless a newer v0.5 tag appears first.
- vue-oauth-layer `README.md` inside `v0.1.0` still says the tag does not exist yet. The release order tagged the existing commit and did not add a README commit. The tag was not moved. "No tag has been pushed" is still true, because there is no remote.
- `state.advance-plan` was not run. It would move Current Position, which is phase 33. Roadmap 32.1-05 was checked by editing ROADMAP.md directly.
## User Setup Required
Create `git@git.golem15.com:golem15/vue-oauth-layer.git`, then push `main` and the annotated tag `v0.1.0` from `/media/nvme/dev/golem15/summercms.io/summercms/vue-oauth-layer`. Do not force-push. Until that remote exists, apps cannot pin the layer. The tagged README still describes the pre-tag install shape.
No journal token was printed, copied, or minted.
## Next Phase Readiness
- The three MCP OAuth gaps are on the tags above. No application go.mod or submodule pointer was bumped.
- Phase 33's release ledger must treat v0.5.2 as already published. Its framework seams belong on a later patch.
- Current Position was left on phase 33.
## Known Stubs
- `vue-oauth-layer/README.md` line 9, inside tag `v0.1.0`: "That tag does not exist yet." The local tag exists; the remote does not. Not edited, because editing would require moving the tag.
## Self-Check: PASSED
- FOUND: `32.1-05-release-decision.txt` (sha256 `3e33d20e4c626c7c43d5da66930ac4b51a0cc02d2995c1fc7e6d5e59f638fa8f`, first line `tag-and-publish`, not rewritten after the tags)
- FOUND: `32.1-05-changelog-notes.md`
- FOUND: summercms.go `9094bf9`, sm-user-plugin `756797c`, sm-oauthserver-plugin `4f8618e` and `a7743e7`
- FOUND remote tags: `v0.5.2`, `v0.1.16`, `v0.1.4`. Local only: vue-oauth-layer `v0.1.0`
- Plan task-4 python verify exit 0. Changelog URL https://summercms.io/changelog/summercms-0-5-2 contains the posted title.
---
*Phase: 32.1-mcp-oauth-for-plugin-apps-declared-scopes-mcp-subject-on-con*
*Completed: 2026-10-28*

View File

@@ -0,0 +1,29 @@
## Highlights
SummerCMS 0.5.2 lets an MCP OAuth agent use the scopes a plugin declares, and lets a tool call see which subject invoked it. sm-user-plugin v0.1.16 applies read and write as implied scopes for OAuth subjects only. sm-oauthserver-plugin v0.1.4 stores one consent per MCP client, replaces it on a later allow, and backfills live grants. vue-oauth-layer v0.1.0 is the `/connect` page for that consent. Together these versions close the three gaps sm-servers-app needs before MCP OAuth can be switched on: the same tool list as a personal token, attribution of the caller, and per-client revoke.
## Added
- One MCP scope list. Plugins publish member-token scopes, the OAuth server advertises that list (optionally filtered), and the protected-resource metadata uses the same names. An empty list still means the five fixed scopes, including backend. OIDC discovery is unchanged.
- An MCP call on the request context: guard, user, client, token, scopes, session and tool. A request that is not an MCP tool call has none.
- A pending consent view reports whether offline access was requested.
- sm-user-plugin v0.1.16 expands a declared scope when an OAuth grant holds the read or write that the scope marks as implied. A personal token is not expanded, write does not imply read, and the stored subject scopes stay as issued. The dispatch credential still carries the personal token id.
- sm-oauthserver-plugin v0.1.4 records MCP consent per client, shows scope details on the consent JSON, marks authorizations as mcp or oidc, and backfills a consent for each live grant. A second migrate inserts nothing.
- vue-oauth-layer v0.1.0 renders `/connect` from that JSON: checkboxes, read locked, the administrator named as text, and a refetch when the backend link changed. The layer's git remote is not published yet, so an app cannot pin the tag until that repository exists.
## Changed
- A later MCP allow replaces the stored consent scopes. It does not merge them with the previous grant.
- Unticking offline access clears that flag on the issued code. Omitting the scopes field leaves the pending flag as it was.
- Revoking an authorized MCP client deletes its unused code and leaves the user's other clients in place.
- sm-oauthserver-plugin v0.1.4 requires SummerCMS v0.5.2 and sm-user-plugin v0.1.16.
- sm-user-plugin v0.1.16 is not a descendant of v0.1.15. It does not include the missing-scope and missing-permission fields from that tag. Build it with SummerCMS v0.5.2; its go.mod still states v0.5.0 and selects the newer framework only when the application does.
## Fixed
- A hidden relation field or partial field no longer keeps its routes after it is removed from the form.
- Record events fire when a hasMany child is linked, unlinked, or attached from a deferred commit, and the event locale is the request locale's primary tag.
- A widget action dispatched while the widget connects is delivered.
- Uploading through a form extension follows that extension's visibility.
- A required field that belongs to a form extension is checked on the extension's own value, so saving the host form no longer fails on a rule the owner model cannot satisfy.
- The additive API check compares the new release with the previous one after the tree is tagged.

View File

@@ -0,0 +1,70 @@
tag-and-publish
framework yes
v0.1.1
v0.1.10
v0.1.11
v0.1.12
v0.1.13
v0.1.14
v0.1.15
v0.1.16
v0.1.17
v0.1.18
v0.1.19
v0.1.2
v0.1.20
v0.1.21
v0.1.22
v0.1.23
v0.1.24
v0.1.25
v0.1.26
v0.1.27
v0.1.3
v0.1.4
v0.1.5
v0.1.6
v0.1.7
v0.1.8
v0.1.9
v0.2.0
v0.2.1
v0.2.2
v0.2.3
v0.2.4
v0.3.0
v0.3.1
v0.4.0
v0.4.1
v0.4.2
v0.4.3
v0.4.4
v0.5.0
v0.5.1
.
user yes
v0.1.0
v0.1.1
v0.1.10
v0.1.11
v0.1.12
v0.1.13
v0.1.14
v0.1.15
v0.1.2
v0.1.3
v0.1.4
v0.1.5
v0.1.6
v0.1.7
v0.1.8
v0.1.9
.
oauth yes
v0.1.0
v0.1.1
v0.1.2
v0.1.3
.
layer no
.