LearnNewsExamplesServices
Frontmatter
id16736
titleForge-PAT admission at the fleet surface — subject = ownerPrincipal
stateClosed
labels
enhancementai
assigneesneo-fable-clio
createdAtAug 8, 2026, 9:56 PM
updatedAtAug 14, 2026, 7:39 PM
githubUrlhttps://github.com/neomjs/neo/issues/16736
authorneo-fable-clio
commentsCount1
parentIssue16168
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[ ] 16737 Viewer-scoped roster projection under the truth-preserving presence contract
closedAtAug 14, 2026, 7:39 PM
milestonev13.2

Forge-PAT admission at the fleet surface — subject = ownerPrincipal

Closed Backlog/active-chunk-14 enhancementai
neo-fable-clio
neo-fable-clio commented on Aug 8, 2026, 9:56 PM

Graduated from D#16720 (body v12 @ 2026-08-08T19:52:47Z). Concept 3: PAT-grade auth by ADOPTING shipped substrate — authentication source, never authorization.

Context

ai/mcp/server/shared/services/AuthService.mjs ships the forge-PAT contract (NEO_AUTH_MODElocal-bearer/gitlab-pat/github-pat, #12378/#12383): self-validated bearer, validated forge identity as caller identity. The fleet surface takes the same seat. Per learn/agentos/cloud-deployment/ClientAuthentication.md, forge auth establishes identity — Fleet authorization is the grant families' job (S5).

Acceptance Criteria

  • The fleet service validates Authorization: Bearer via AuthService's existing modes — no new issuance machinery.
  • Admission subject = the stable ownerPrincipal ((authProvider, normalizedProviderBaseUrl, providerUserId) — S4's build), NEVER the mutable login; login is retained as display projection only.
  • local-bearer mode decision recorded (OQ4 carrier): keep the process-bearer dev convenience or require PAT everywhere — decide + document.
  • Read-observe vs lifecycle-write scope semantics per verb class (the R3 seam) enforced at admission.
  • Doc surfaces updated (consumer-sweep ⚠): ClientAuthentication.md, the local-agent-os lifecycle README.

Contract Ledger (T3)

Surface-Anchor V-B-A per row ran at intake (2026-08-14, exact head — see the intake classification comment). ADR 0038 is the surface authority; this matrix binds it to the edit surfaces rather than restating it.

Target Surface Source of Authority Proposed Behavior Fallback / Edge Case Docs Evidence
Fleet HTTP admission (startFleetServer auth chain) ADR 0038 §2.5.1 row 1 + AuthService modes (verified: local-bearer/gitlab-pat/github-pat) Authorization: Bearer <forge-PAT> validated by the configured mode; admitted requests carry the frozen allowlisted request context (shipped S1 behavior, adopted not rebuilt) Missing/invalid bearer → 401 wire refusal; minted non-forge tokens refused by mode ClientAuthentication.md FleetServerComposition.spec.mjs real-server admission tests (existing, extended)
deriveOwnerPrincipal(requestContext) — NEW, the one named seam ADR 0038 §2.2 fact 2 (stable subject ≠ mutable login) + D#16720 Concept 3 Pure derivation (authProvider, normalizedProviderBaseUrl, providerUserId) from the frozen context; stamped as THE admission subject; login retained as display projection only Any tuple member absent → no subject → refusal (NEVER a login fallback) JSDoc + ClientAuthentication.md Unit falsifiers incl. login-mutation invariance (login changes, principal stable)
resolveViewerStreamKey (existing consumer) fleetServer.mjs (verified: keys provider:<authProvider>:<providerUserId>, no base-url element) Alignment decision recorded in-lane: converge onto the principal seam or document the divergence Unkeyable viewer → existing 403 refusal (unchanged) JSDoc Existing stream-key specs + one alignment falsifier
Verb-class scopes (fleetServerPolicy.mjs → dispatch) — the R3 seam ADR 0038 §2.5.1 row 1 Scopes column (read ÷ lifecycle, distinct envelopes per verb class, never one blanket scope) Every wire verb classified read-observe vs lifecycle-write; the class split enforced at admission (S5's grant verbs later consume the classes) Unknown verb → existing unsupported-method; UNCLASSIFIED verb → fail-closed refusal Policy JSDoc Policy spec: classification total-coverage + fail-closed falsifier
local-bearer at the fleet surface (OQ4 carrier) D#16720 OQ4 DECISION recorded in this lane (keep dev convenience vs require PAT everywhere), with rationale Per decision ClientAuthentication.md + lifecycle README Decision recorded + mode-gated spec

Sequencing

Blocks S3/S4/S5 (they consume the admission identity).

Signal Ledger

Family-keyed at D#16720 v11/v12: fable AUTHOR_SIGNAL + APPROVED; Opus APPROVED. Full ledger: D#16720 closing comment.

Unresolved Dissent

GPT v9-anchor DEFERRED: repair implemented (v11); re-stamp pending.

Unresolved Liveness

@neo-gemini-pro benched; GPT/Kimi engaged without final-anchor signal.

Discussion Criteria Mapping

D#16720 criteria (1)–(9): closing comment.

Origin: D#16720 · Retrieval Hint: "fleet surface forge-PAT admission AuthService ownerPrincipal subject local-bearer decision"

tobiu referenced in commit 912db48 - "feat(ai): fleet admission derives the ownerPrincipal subject + the R3 verb-class split (#16736) (#17127) on Aug 14, 2026, 7:39 PM
tobiu closed this issue on Aug 14, 2026, 7:39 PM