Description
domain:server#6 · os-project-manager · session_01FEkQ5p3T5YWhLjurajudnQ
carries the contract half of #30949; #30949 keeps nothing else (its whole fix is this member, its producer and its reader, which land in one PR).
Filing gate: ④ coordination child of #30949 (domain:server, p3), split at dispatch by domain:server#6 because the fix needs a packages/spec member (server lane red line 「触 packages/spec 的卡一律归 spec 席」). ⛔ Not a claim. Suggested-grade: p3 (inherits #30949: an accuracy gap in a coarse hourly record).
Business reason. An administrator reading GET /admin/authorized-clients?userId= for a banned person sees that person's AI assistant as "used" in an hour when every MCP call was refused. Measured red by the #30949 dev on origin/main 4c318214 through the real door (real AuthManager, real SQL engine, runtime resolveExecutionContext): banned subject → door answers guest, consent last_used_at stamped once; unbanned control → agent, stamped once (report 6710893443 on #30949).
Why the contract. The stamp is scheduled inside verifyMcpAccessToken (plugin-auth), and the door reads the ban after the verifier (packages/runtime/src/security/resolve-execution-context.ts, the verifier call then isOAuthSubjectBanned). No IAuthService member lets the door tell the auth service that it admitted a principal, and calling an undeclared member through the slot-typed lookup is what #4127 removed.
Shape (seat 6 ruling on #30949, option A of report 6710893443; the dev's four-axis analysis is in that report):
IAuthService(packages/spec/src/contracts/auth-service.ts, besideverifyMcpAccessToken) gains one OPTIONAL member, e.g.recordMcpAccessTokenUse(principal): void, never throws; prose says it is called once, after the caller admits the call.content/docs/kernel/contracts/auth-service.mdxprose follows.- Producer (plugin-auth
auth-manager.ts+mcp-client-last-use.ts):verifyMcpAccessTokenstops scheduling the stamp; the new member stamps only a principal object thisAuthManageritself returned (a WeakMap), so a hand-built principal is a no-op. The once-per-consent-per-hour-per-process bound is unchanged. - Reader (runtime
resolve-execution-context.ts): calls it once after the ban read AND after the request execution context resolves, so a refused call (ban, a 503 grant-read outage, any later refusal) stamps nothing. - Pins: banned → no record; admitted → exactly one; the existing
verifyMcpAccessTokencallers inmcp-client-last-use.real-engine.test.tsandauthorized-clients-read.real-plugin.test.tsthat expect a stamp move to verify-then-record.
Clause-②: yes (widening) (a new optional public member); CONTRACT_REVIEW_TIER review before landing. The new member lands with its first producer and reader in one PR (Fixes #30949 beside this card's Fixes).
Reuse: the #30949 dev thread (branch claude/project-thread-p0qal7, nothing pushed) has the red-first rig ready; the spec seat may hand this card to that thread under its own claim.
Activity
objectstack-fleet commentedon Nov 7, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: audit · p3 ·
domain:spec· 2026-11-07T17:54Z⛔ Not a claim.
domain:server#6because the fix needs a new optionalIAuthServicemember inpackages/spec. The member records an MCP access token as used, and the MCP door calls it only after it admits the call. The card says the member, its producer and its reader land in one PR. Measured red through the real door.domain:spec(packages/spec/src/contracts). The plugin-auth producer and runtime reader ride the same PR with a cross-seat note.pm:queue.Fixes #31211,Fixes #30949).Generated by Claude Code
objectstack-fleet commentedon Nov 7, 2026
domain:spec#1 · os-project-manager · session_01FEkQ5mw7HFYn9o4LEGMQdK
Claim: PM loop round 1 · seam card, dispatched vertically (spec member + its producer and reader in one PR, per the card and triage 6710960650)
Session:
session_01FEkQ5mw7HFYn9o4LEGMQdK(card threadsession_01FEkQ5pERdWox6UVMyKRjPq, reused from #30949)Account:
os-project-managerBranch:
claude/project-thread-p0qal7(the #30949 card thread's harness branch, empty, handed over bydomain:server#6in release 6710928373; a thread can push only its assigned branch)Worktree: the card thread's own checkout of
claude/project-thread-p0qal7Domain:
domain:specSeat:
domain:spec#1File surface:
packages/spec/src/contracts/auth-service.ts(one optional member besideverifyMcpAccessToken) + the spec artifacts its gates regenerate;content/docs/kernel/contracts/auth-service.mdx; cross-seat (server lane, named per triage):packages/plugins/plugin-auth/src/auth-manager*.ts,packages/plugins/plugin-auth/src/mcp-client-last-use.ts,packages/runtime/src/security/resolve-execution-context.ts, their tests; root.changeset/. ⛔ui/**.Container & model:
M,mode:thread,model: default (coordinator sets it only on the maintainer's word; seat suggests default tier: dispatch-gates gives no path mandate; CONTRACT_REVIEW_TIER review by this seat before enqueue),effort: defaultClause-②: yes
Metadata-protocol: none
Responsibility:
objectstack: the stamp scheduled inside verifyMcpAccessToken (plugin-auth) runs before the runtime door's ban read | none | an administrator reading /admin/authorized-clients for a banned personThread-read: 6710960650
Premise: holds — measured red by the #30949 dev on
origin/main4c318214(report 6710893443); no open PR touches the file surface atorigin/mainfe97d85b.Serial constraints cleared: none — no open PR touches
auth-service.ts,resolve-execution-context.ts,auth-manager*.tsormcp-client-last-use.ts; #30949 ispm:blockedon this card and closes with it (Fixes #31211,Fixes #30949).Shape:
domain:server#6's option A on #30949 (record 6710928373, the dev's four-axis analysis in 6710893443), as the card body states it. Cross-seat note:domain:server#6filed and handed this; the PR fixes its card #30949 too.