Context
Phase-1 leaf of epic #15798 (Discussion #15595, OQ1 contract 2 of the four-contract decomposition from fold 2). When KB/MC become long-running shared HTTP servers locally, per-seat identity moves from process-possession to request-time proof — the fold-2 finding: local-bearer is possession-only with no token→AgentIdentity map, "the crown-jewel gap for shared local servers." The multi-clone reality (N seats → 1 shared plane) makes this multi-client-one-stack auth, not per-seat config.
The Problem
Contract 2 (request-time subject binding) has no mechanism today. Contracts 1/3 (credential lifecycle, identity lifecycle) have the wake-subscription analog per fold 3; contract 4 (authorization separation) is genuinely new design and explicitly deferred (Out of Scope). The #14388 auth≠admission lesson binds: authenticating a transport is not admitting a subject.
The Architectural Reality
The in-tree precedent is the trusted window-identity spine (#15514 / PR #15529, merged): a one-time capability minted by the owner, consumed exactly once at the handshake, bound to exactly one runtime identity, generation-invalidated on reload/replacement, fail-closed for everything stale. Precedent transfer per the fold-6 ported analysis: seat-config generator mints → seat consumes at boot handshake → rotation invalidates the generation. Plane scoping: tokens bind subject-to-planeId (from #15799) so a seat admitted to an overlay plane cannot present against the durable plane.
The Fix (one PR)
Implement contract 2 for the parity HTTP path: mint (generator-side), bind-once-per-generation admission (server-side — the consume-once transfer, PR #15832 Delta 1), token→AgentIdentity subject binding, generation invalidation, fail-closed stale handling; bind admission to the declared planeId. Exemplar coverage on Memory Core's HTTP transport; KB follows the same seam.
Contract Ledger
(Derived at intake 2026-07-24 by the claimer with Surface-Anchor V-B-A — the body predated the ledger gate; anchors verified against current dev: AuthService.mjs:66-68 documents local-bearer as "possession-only: no PRM, discovery, identity lookup, or provisioning" — the premise, at source; the precedent's private-route shape from PR #15529's shipped contract.)
(Row 1 + AC1 restated 2026-07-24 per PR #15832 review PRR_kwDODSospM8AAAABHK9rpg §5.2 "satisfy or restate": consume-once → bind-once-per-generation, the PR's argued Delta 1; restatement recorded in the ticket comment thread, confirmation requested from the ticket author.)
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback |
Docs |
Evidence |
MC HTTP auth path (AuthService mode surface + auth.* config leaves) |
this ticket + #15514/PR #15529 precedent + ADR 0019 (any new leaf: read-gate + leaf shape) |
request-time subject binding: a seat token bound once per config generation resolves to its minted AgentIdentity (consume-once transferred as bind-once-per-generation — PR #15832 Delta 1); possession-only local-bearer remains the loopback-only dev mode, never the parity path |
malformed-token / wrong-plane / stale-generation / unknown-token → named fail-closed rejection (401-class; no consumed class — nothing is consumed under the generation bind) |
auth section of the server docs + OpenAPI auth notes |
the five precedent properties as specs (mint-once / bind-once-per-generation / bind-one / generation-invalidate / fail-closed) |
| Seat-config generator (mint side) |
#15805 consumer contract (the generator is the single authoring surface) |
mints ONE one-time token per seat per config generation, generator-private (never in public config surfaces — the opaqueHandleKey discipline); regeneration invalidates prior generations |
seat config without a token = stdio wiring untouched |
generator docs |
mint + generation-invalidation specs |
Token→AgentIdentity binding + RequestContextService propagation |
#14388 auth≠admission lesson |
the resolved subject propagates as the caller identity through the existing context chain; admission is plane-scoped (subject×plane.id, the #15799 leaf) |
cross-plane presentation → named fail-closed error |
ADR 0019 §10.6-adjacent note |
binding + cross-plane rejection specs |
| stdio transport path |
epic non-goal (explicit) |
untouched |
n/a |
body note |
existing stdio specs stay green |
Acceptance Criteria
Out of Scope
Contract 4 (authorization separation — later sub); contracts 1/3 beyond reusing their existing lifecycle shapes; any Fleet read-model changes (OQ2's submatrix stays in its own lane).
Related
Epic #15798 · blocked_by #15799 · precedent #15514 / PR #15529 · fold-2 OQ1 decomposition + #14388 lesson (D#15595) · borrowed-authority caveat as in #15799.
Origin Session ID: 758f110e-a429-4597-beb0-5fd3ec7d1bfc
Retrieval Hint: query_raw_memories("OQ1 contract 2 request-time subject binding window identity spine transfer")
Context
Phase-1 leaf of epic #15798 (Discussion #15595, OQ1 contract 2 of the four-contract decomposition from fold 2). When KB/MC become long-running shared HTTP servers locally, per-seat identity moves from process-possession to request-time proof — the fold-2 finding:
local-beareris possession-only with no token→AgentIdentitymap, "the crown-jewel gap for shared local servers." The multi-clone reality (N seats → 1 shared plane) makes this multi-client-one-stack auth, not per-seat config.The Problem
Contract 2 (request-time subject binding) has no mechanism today. Contracts 1/3 (credential lifecycle, identity lifecycle) have the wake-subscription analog per fold 3; contract 4 (authorization separation) is genuinely new design and explicitly deferred (Out of Scope). The
#14388auth≠admission lesson binds: authenticating a transport is not admitting a subject.The Architectural Reality
The in-tree precedent is the trusted window-identity spine (#15514 / PR #15529, merged): a one-time capability minted by the owner, consumed exactly once at the handshake, bound to exactly one runtime identity, generation-invalidated on reload/replacement, fail-closed for everything stale. Precedent transfer per the fold-6 ported analysis: seat-config generator mints → seat consumes at boot handshake → rotation invalidates the generation. Plane scoping: tokens bind subject-to-
planeId(from #15799) so a seat admitted to an overlay plane cannot present against the durable plane.The Fix (one PR)
Implement contract 2 for the parity HTTP path: mint (generator-side), bind-once-per-generation admission (server-side — the consume-once transfer, PR #15832 Delta 1), token→
AgentIdentitysubject binding, generation invalidation, fail-closed stale handling; bind admission to the declaredplaneId. Exemplar coverage on Memory Core's HTTP transport; KB follows the same seam.Contract Ledger
(Derived at intake 2026-07-24 by the claimer with Surface-Anchor V-B-A — the body predated the ledger gate; anchors verified against current dev:
AuthService.mjs:66-68documents local-bearer as "possession-only: no PRM, discovery, identity lookup, or provisioning" — the premise, at source; the precedent's private-route shape from PR #15529's shipped contract.)(Row 1 + AC1 restated 2026-07-24 per PR #15832 review
PRR_kwDODSospM8AAAABHK9rpg§5.2 "satisfy or restate": consume-once → bind-once-per-generation, the PR's argued Delta 1; restatement recorded in the ticket comment thread, confirmation requested from the ticket author.)AuthServicemode surface +auth.*config leaves)AgentIdentity(consume-once transferred as bind-once-per-generation — PR #15832 Delta 1); possession-onlylocal-bearerremains the loopback-only dev mode, never the parity pathmalformed-token/wrong-plane/stale-generation/unknown-token→ named fail-closed rejection (401-class; noconsumedclass — nothing is consumed under the generation bind)opaqueHandleKeydiscipline); regeneration invalidates prior generationsAgentIdentitybinding +RequestContextServicepropagation#14388auth≠admission lessonplane.id, the #15799 leaf)Acceptance Criteria
AgentIdentity, never possession-only, on the parity HTTP path.planeId); cross-plane presentation fails closed with a named error.Out of Scope
Contract 4 (authorization separation — later sub); contracts 1/3 beyond reusing their existing lifecycle shapes; any Fleet read-model changes (OQ2's submatrix stays in its own lane).
Related
Epic #15798 · blocked_by #15799 · precedent #15514 / PR #15529 · fold-2 OQ1 decomposition +
#14388lesson (D#15595) · borrowed-authority caveat as in #15799.Origin Session ID: 758f110e-a429-4597-beb0-5fd3ec7d1bfc Retrieval Hint:
query_raw_memories("OQ1 contract 2 request-time subject binding window identity spine transfer")