Graduated from D#16720 (FM client-side migration delta, body v12 @ 2026-08-08T19:52:47Z; final family-keyed quorum: fable AUTHOR_SIGNAL + APPROVED · Opus APPROVED (re-stamped, blockers verified closed) · GPT [GRADUATION_APPROVED] @ v12, findings closed + defer-closed at filed state). Matrix Option A — the #16176-inherited phase-2 selection, confirmed by the day's live receipts.
Context
The cockpit's fleet truth must be served from where the data lives. Today the shell spawns a host-side devFleetServer (ai/services/fleet/devFleetServer.mjs) that resolves ONE viewer at process boot and reads a host registry which does not exist post-hard-cut (root-cause receipt on #16699); fleetBridgeServer.mjs stamps that boot-bound viewer on every request behind one ephemeral local bearer. The composition (ai/deploy/docker-compose.local-agent-os.yml) carries chroma/kb/mc/orchestrator/ingress — no fleet service.
This is an auth/identity boundary change, not a Compose-only relocation (intake falsifier 1, 2026-08-08): GitHub PATs admitted by AuthService are not accepted by the current Fleet guard; the current server cannot simply become the image entrypoint.
Scope
Add the OPTIONAL fleet-server compose service: the same AuthService seat kb/mc occupy, serving the fleet wire from inside the composition — with a request-time identity boundary replacing the boot-bound viewer.
Contract Ledger
| Target surface |
Authority (current) |
Pinned behavior (this leaf) |
Fail-closed / fallback |
Docs consumer |
Evidence |
fleet-server service + profile |
ai/deploy/docker-compose.yml + docker-compose.local-agent-os.yml layering (base/local); no fleet service today |
EXTEND the existing base/local layering — no seventh bespoke composition file. Local Agent OS + downloadable FM profile REQUIRE the service (fresh install renders a live plane-owned roster); headless cloud omits it. Ingress must NOT hard-depend on fleet-server: a Fleet-less headless profile stays valid. |
Absent service ⇒ cockpit shows the topology-aware disconnected banner (#16721 vocabulary), never a crash. |
Deployment runbook + FM install guide |
Rendered docker compose config witness for BOTH profiles (with + without service) |
| Fleet HTTP entrypoint |
devFleetServer.mjs (one viewer at boot) + fleetBridgeServer.mjs (ephemeral local bearer stamping that viewer per request); current AuthService PAT verification emits provider-validated facts; no ownerPrincipal field exists anywhere today |
Request-time AuthService admission (same seat kb/mc occupy) → an immutable per-request context carrying the provider-validated AuthInfo facts emitted by AuthService (authProvider, providerBaseUrl, providerUserId, display login); no ownerPrincipal exists in S1 — its derivation/normalization stays S2 #16736 + S4 #16738 authority. Boundary: S1 composes the generic AuthService-backed HTTP entrypoint, exact routes, storage root, and read-only/probe surface; S2 owns the Fleet-specific forge-mode/admission policy and stable-principal subject semantics. NO boot-bound viewer in the composed entrypoint. |
Unadmitted request ⇒ refused with explicit auth error; no anonymous fallback identity; every principal-bound verb fails closed with the declared degraded: awaiting-<slice> marker until S2 + S4 land. |
ADR carrier #16747 (pure-client topology) |
Auth witness (S1-bounded): PAT admitted / anonymous refused / served request-identity facts match the provider-validated AuthInfo; stable-principal equality becomes S2/S4 evidence |
/fleet + /fleet/probe routes |
ai/deploy/Caddyfile.local-agent-os (local: loopback HTTP) + ai/deploy/Caddyfile (cloud: TLS-terminating) — the wire exact-matches /fleet and /fleet/probe |
Public path = upstream path, EXACT match (no handle_path prefix-strip — it would miss both routes). Identity-header stripping at ingress per the canonical kb/mc pattern; Host/CORS policy identical to the kb/mc routes. Local = loopback HTTP; cloud = Caddy-terminated TLS (the graduated body's "TLS pass-through" wording is RETIRED — not the canonical pattern). |
Route absent (headless) ⇒ 404 from ingress; no fleet leak. |
Deployment runbook |
Caddy route witness in both profiles; probe reachable only authenticated |
| Fleet data root |
No declarative member exists today; registry/tenant default checkout-relative .neo-ai-data/fleet (intake falsifier 2) |
NEW declarative AiConfig.fleet.dataDir leaf per ADR 0019: leaf(default, env, type) — entrypoint-fixed, read at the use site; explicit planeMember decision per ADR 0019 §10.5 (an anchored leaf with no decision fails closed); ONE Fleet-owned named volume covering keys + ciphertext CO-LOCATED. No use-site env re-derivation, no runtime mutation, no defensive ?.. |
Missing/unplaced root ⇒ boot refusal (member-coherence walk), never a silent checkout-relative fallback. |
ADR 0019 + #16747 |
Persistence witness: volume survives container recreation; boot-refusal witness on unplaced root |
| S1 wire availability |
n/a (new service); ADR 0038 §2.2 fact 3 binds: roster visibility is DEFAULT-PRIVATE, never inferred from authentication or team membership |
S1 serves EXACTLY the authenticated identity-bearing /fleet/probe. ALL owner-scoped Fleet-state reads — roster (listAgents/getAgent) AND the tenant registry (listTenants) — are principal-bound by construction (ADR 0038 §2.2 fact 2: Fleet state is ownerPrincipal-owned) and FAIL CLOSED until their named slices land: S4 #16738 (principal) + S5 #16739 (CAN_OBSERVE_FLEET_OF enforcement) + S3 #16737 (viewer-scoped projection). Auth-only visibility is FORBIDDEN, not deferred — serving the whole roster behind bare admission would implement the inference the ADR bans. Principal-bound WRITES (grants, roster-projection writes, lifecycle mutation) identically fail closed (S2 #16736 · S4 · S5). The implementing PR carries the exact verb table; this leaf pins the CLASS split. |
Refused verb ⇒ explicit degraded: awaiting-<slice> marker, never a partial success and never an auth-only fallback view. |
Cockpit connection-truth surface (#16721) + ADR 0038 §2.2 |
Wire witness: probe succeeds authenticated; roster/tenant/principal-bound verbs return the declared refusal — a witness asserting listAgents succeeds behind bare auth is itself the defect |
| Health / readiness |
Composition's node-service healthcheck discipline (kb/mc); the existing helper is MCP-specific (intake falsifier 4) |
Readiness = authenticated identity-bearing probe proving AuthService admission + served identity + fixed Fleet root — NOT a bare TCP-listener check. |
Failing probe ⇒ compose-unhealthy; dependent tooling sees it. |
Deployment runbook |
Healthcheck witness in rendered compose + live probe receipt |
| Storage boundary (the STEP_BACK ✗ repair, binding) |
#16176 Diamond-1 Option A (selected); the shared-volume facade is its REJECTED Option B |
The service owns a Fleet-owned entrypoint-fixed durable root — scoped to what S1 actually owns: registry, tenant, key material. Grants-ledger durability = S6 #16740; audit + lifecycle durable stores = their named later slices. S1 creates NONE of those stores. Graph/mailbox/roster facts cross authenticated registered projections / service APIs — NEVER a mount or schema-read of another service's private storage. |
Cross-plane read without a registered projection ⇒ architectural rejection at review. |
#16168 (parent) + #16747 |
Review-gate + projection-only wire witness |
Acceptance Criteria
Sequencing
- #16715 / PR #16731 (pure plan / host apply split): DISCHARGED — merged 2026-08-08 (
10591e80e5).
- Merge-order dependency: #16747 (ADR carrier amending ADR 0020/0026, recording the pure-client topology). The ADR lands first or in the same window; this leaf cites it — D1 wants early authoring for exactly this reason.
- Blocked by: none — claimable after revalidation of this repaired body.
Signal Ledger
Family-keyed at D#16720 final filed state: fable AUTHOR_SIGNAL + APPROVED (re-bound) · Opus APPROVED (re-stamped, both blockers verified closed at source) · GPT [GRADUATION_APPROVED] @ body-19:52:47Z (findings closed at v12; defer-closed 20:06Z; filed C5 graph verified). Full ledger: D#16720 closing comment. (Supersedes the filing-time "GPT re-stamp pending" prose — the re-stamp landed.)
Unresolved Dissent
None open. The v9-anchor GPT DEFERRED (parent-authority collision) was repaired in v11 and closed by the v12 [GRADUATION_APPROVED] + defer-closed receipts.
Unresolved Liveness
@neo-gemini-pro benched. Kimi engaged (falsifier cycles / seat witness) without final-anchor signal — recorded, never implied consent.
Discussion Criteria Mapping
D#16720 criteria (1)–(9): see the closing comment's receipts. Intake alignment (this body v2): the [ARCH_ALIGNMENT] comment of 2026-08-08T20:59Z — all six ledger rows adopted; falsifiers 1–5 addressed in place.
Intake alignment (v3): the [REVALIDATION] comment of 2026-08-08T21:4xZ — the ownerPrincipal sequencing contradiction repaired per its four exact points (S1 = provider-validated AuthInfo facts; principal derivation = S2/S4; boundary sentence; S1-bounded auth witness). Truth-fold (v4, 2026-08-09): the S1 ready-read row narrowed per the PR #16761 review's authority delta — probe-only S1; roster + tenant-registry reads classified owner-scoped and fail-closed to S3/S4/S5; auth-only visibility named FORBIDDEN per ADR 0038 §2.2 fact 3 (default-private is accepted authority, not a preference).
Origin: D#16720 · Body v4 (contract-aligned 2026-08-08; visibility truth-fold 2026-08-09) · Retrieval Hint: "fleet-server compose service optional AuthService seat provider-validated AuthInfo Fleet-owned durable root registered projections"
Graduated from D#16720 (FM client-side migration delta, body v12 @ 2026-08-08T19:52:47Z; final family-keyed quorum: fable AUTHOR_SIGNAL + APPROVED · Opus APPROVED (re-stamped, blockers verified closed) · GPT [GRADUATION_APPROVED] @ v12, findings closed + defer-closed at filed state). Matrix Option A — the #16176-inherited phase-2 selection, confirmed by the day's live receipts.
Context
The cockpit's fleet truth must be served from where the data lives. Today the shell spawns a host-side
devFleetServer(ai/services/fleet/devFleetServer.mjs) that resolves ONE viewer at process boot and reads a host registry which does not exist post-hard-cut (root-cause receipt on #16699);fleetBridgeServer.mjsstamps that boot-bound viewer on every request behind one ephemeral local bearer. The composition (ai/deploy/docker-compose.local-agent-os.yml) carries chroma/kb/mc/orchestrator/ingress — no fleet service.This is an auth/identity boundary change, not a Compose-only relocation (intake falsifier 1, 2026-08-08): GitHub PATs admitted by
AuthServiceare not accepted by the current Fleet guard; the current server cannot simply become the image entrypoint.Scope
Add the OPTIONAL
fleet-servercompose service: the sameAuthServiceseat kb/mc occupy, serving the fleet wire from inside the composition — with a request-time identity boundary replacing the boot-bound viewer.Contract Ledger
fleet-serverservice + profileai/deploy/docker-compose.yml+docker-compose.local-agent-os.ymllayering (base/local); no fleet service todaydocker compose configwitness for BOTH profiles (with + without service)devFleetServer.mjs(one viewer at boot) +fleetBridgeServer.mjs(ephemeral local bearer stamping that viewer per request); currentAuthServicePAT verification emits provider-validated facts; noownerPrincipalfield exists anywhere todayAuthServiceadmission (same seat kb/mc occupy) → an immutable per-request context carrying the provider-validated AuthInfo facts emitted byAuthService(authProvider,providerBaseUrl,providerUserId, display login); noownerPrincipalexists in S1 — its derivation/normalization stays S2 #16736 + S4 #16738 authority. Boundary: S1 composes the generic AuthService-backed HTTP entrypoint, exact routes, storage root, and read-only/probe surface; S2 owns the Fleet-specific forge-mode/admission policy and stable-principal subject semantics. NO boot-bound viewer in the composed entrypoint.degraded: awaiting-<slice>marker until S2 + S4 land./fleet+/fleet/proberoutesai/deploy/Caddyfile.local-agent-os(local: loopback HTTP) +ai/deploy/Caddyfile(cloud: TLS-terminating) — the wire exact-matches/fleetand/fleet/probehandle_pathprefix-strip — it would miss both routes). Identity-header stripping at ingress per the canonical kb/mc pattern; Host/CORS policy identical to the kb/mc routes. Local = loopback HTTP; cloud = Caddy-terminated TLS (the graduated body's "TLS pass-through" wording is RETIRED — not the canonical pattern)..neo-ai-data/fleet(intake falsifier 2)AiConfig.fleet.dataDirleaf per ADR 0019:leaf(default, env, type)— entrypoint-fixed, read at the use site; explicitplaneMemberdecision per ADR 0019 §10.5 (an anchored leaf with no decision fails closed); ONE Fleet-owned named volume covering keys + ciphertext CO-LOCATED. No use-site env re-derivation, no runtime mutation, no defensive?../fleet/probe. ALL owner-scoped Fleet-state reads — roster (listAgents/getAgent) AND the tenant registry (listTenants) — are principal-bound by construction (ADR 0038 §2.2 fact 2: Fleet state isownerPrincipal-owned) and FAIL CLOSED until their named slices land: S4 #16738 (principal) + S5 #16739 (CAN_OBSERVE_FLEET_OFenforcement) + S3 #16737 (viewer-scoped projection). Auth-only visibility is FORBIDDEN, not deferred — serving the whole roster behind bare admission would implement the inference the ADR bans. Principal-bound WRITES (grants, roster-projection writes, lifecycle mutation) identically fail closed (S2 #16736 · S4 · S5). The implementing PR carries the exact verb table; this leaf pins the CLASS split.degraded: awaiting-<slice>marker, never a partial success and never an auth-only fallback view.listAgentssucceeds behind bare auth is itself the defectAcceptance Criteria
fleet-serverservice lands by EXTENDING base/local compose + Caddy layering (both profiles render; no new composition file), with exact-match/fleet+/fleet/proberoutes and kb/mc-identical header/Host/CORS policy.AuthServiceadmission with an immutable per-request context of provider-validated AuthInfo facts — noownerPrincipalin S1 (derivation/normalization stays S2 #16736 + S4 #16738; principal-bound verbs fail closed with the declared degraded marker); the boot-bound viewer is retired from the composed path.AiConfig.fleet.dataDirdeclarative leaf (ADR 0019-conform, explicitplaneMemberdecision) + ONE Fleet-owned named volume (keys + ciphertext co-located); container runs against container-internal data roots with no host checkout (the Matrix-A falsifier).listAgents/getAgent), tenant-registry (listTenants), and all principal-bound verbs fail closed with explicit degraded markers until S3/S4/S5 land — auth-only visibility forbidden per ADR 0038 §2.2.Sequencing
10591e80e5).Signal Ledger
Family-keyed at D#16720 final filed state: fable AUTHOR_SIGNAL + APPROVED (re-bound) · Opus APPROVED (re-stamped, both blockers verified closed at source) · GPT [GRADUATION_APPROVED] @ body-19:52:47Z (findings closed at v12; defer-closed 20:06Z; filed C5 graph verified). Full ledger: D#16720 closing comment. (Supersedes the filing-time "GPT re-stamp pending" prose — the re-stamp landed.)
Unresolved Dissent
None open. The v9-anchor GPT DEFERRED (parent-authority collision) was repaired in v11 and closed by the v12 [GRADUATION_APPROVED] + defer-closed receipts.
Unresolved Liveness
@neo-gemini-pro benched. Kimi engaged (falsifier cycles / seat witness) without final-anchor signal — recorded, never implied consent.
Discussion Criteria Mapping
D#16720 criteria (1)–(9): see the closing comment's receipts. Intake alignment (this body v2): the [ARCH_ALIGNMENT] comment of 2026-08-08T20:59Z — all six ledger rows adopted; falsifiers 1–5 addressed in place.
Intake alignment (v3): the [REVALIDATION] comment of 2026-08-08T21:4xZ — the ownerPrincipal sequencing contradiction repaired per its four exact points (S1 = provider-validated AuthInfo facts; principal derivation = S2/S4; boundary sentence; S1-bounded auth witness). Truth-fold (v4, 2026-08-09): the S1 ready-read row narrowed per the PR #16761 review's authority delta — probe-only S1; roster + tenant-registry reads classified owner-scoped and fail-closed to S3/S4/S5; auth-only visibility named FORBIDDEN per ADR 0038 §2.2 fact 3 (default-private is accepted authority, not a preference).
Origin: D#16720 · Body v4 (contract-aligned 2026-08-08; visibility truth-fold 2026-08-09) · Retrieval Hint: "fleet-server compose service optional AuthService seat provider-validated AuthInfo Fleet-owned durable root registered projections"