You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Problem — The control-grant machinery (scopes, state machine, write gate) exists but is dormant and unseeded: no flow mints a control grant, and lifecycle-admin authority is never established — so a headless peer can never be approved from anywhere. See #1540 for the full design and the independent-peer model. Approach — Seed lifecycle-admin authority at Enroll (record the enroller as the target's authorityIdentityKey, riding the identity-bound enrollment nonce + Observe bootstrap), and extend the self-owned fast-path (the evaluateObserveBootstrap pattern) to mint a control grant on an explicit enable act. Control lands per-session and is never auto-restored. Scope — in: enroll seeding of lifecycle-admin; self-owned control issuance; per-session re-arm semantics. · out: the write plane (#1540 slice 2); UI (slice 4); the shared handshake (slice 5). Assumptions — Enroll already establishes bilateral identity + reader-token Observe; both machines are self-owned by one operator.
Warning
Deliberate-review corrections (2026-09-24) — these BIND over any stale text below.
lifecycle-admin authority is NET-NEW persistence, not a wiring. Today authorityIdentityKey exists only as an injected parameter to the pure isLifecycleAuthority predicate (fleet_control_lifecycle.ts:291/303) — no store, no writer, no resolver. This slice must DEFINE: (a) a persisted authority record, (b) a writer invoked at amico fleet enroll recording the enroller as the target's authority, (c) a resolver answering who holds authority for machine X. The enroll verb (amico-run/fleet_enroll_verb.ts) has no bootstrap/nonce hook today — wiring it is in scope (integration surface, not "unit-testable, no UI").
Self-owned control is a NEW evaluateControlBootstrap, not an extension.evaluateObserveBootstrapexplicitly refuses a control outcome ("there is NO control outcome here — deliberately NOT implemented"). Author a new predicate mirroring its structure; do not "extend" the observe one.
management-verified must be a defined predicate. It is a bare boolean set true only in tests today. Name the identity/transport/token check that establishes it, as an AC.
AC3 is a regression-guard, not new work — control-not-auto-restored is already satisfied by landed fleet_headless_rehydration.ts.
Deliver the requester-side, owner-resolvable, token-bearing grant view Fleet Studio B2b · slice 2 — Observation write plane: control-gated remote writes #1542 needs: the issued control grant records targetMachineId and its token on the controlling machine, plus a read that resolves a grant by targetMachineId === <owner> (grants already carry targetMachineId).
Full record: ADR 0034 decision record (D2/D3).
Acceptance Criteria
amico fleet enroll records the enroller as the target's lifecycle-admin authority (the authorityIdentityKey is persisted and resolvable afterward).
A self-owned, management-verified peer can mint an active control grant via an explicit enable, with no target-side interaction.
A control grant is not auto-restored on rehydration — it lands suspended until an explicit re-enable.
A headless target that ran Enroll yields a lifecycle-admin authority resolvable from the enrolling machine (the target renders nothing).
A shared (non-self-owned) peer does not get the self-owned fast-path — it is held for approval (no privilege bleed).
Testing Decisions
Extend the existing unit suites for fleet_observe_bootstrap (self-owned vs shared decision), fleet_control_lifecycle (grant issuance/state), and fleet_headless_rehydration (control-never-auto-restored). Add an enroll-seeds-lifecycle-admin test. Reuse fleet_two_peer_e2e for the two-machine grant path. Tests assert external behavior (a grant exists/active/suspended; an authority resolves), not internals.
Key Decisions
The self-owned control fast-path mirrors evaluateObserveBootstrap — self-owned + verified management access authorizes the explicit enable; every other case requires approval.
lifecycle-admin is not a superset of control — it mints/revokes/re-admits, it does not itself drive sessions.
Authority is seeded at Enroll, not minted at runtime — this is what makes headless peers approvable from elsewhere.
Constraints & Invariants
Control is never auto-restored (every restart/reconnect leaves it suspended until explicit re-enable).
Headless peers enforce only — they never render approval.
No privilege bleed — a shared peer can never borrow the self-owned fast-path.
Prior Art
Read first (modules): fleet_observe_bootstrap (the self-owned/shared decision + reciprocal grant issuance), fleet_control_lifecycle (scopes, grant state machine, isLifecycleAuthority), fleet_headless_rehydration (the control-suspended-on-rehydration rule), fleet_enrollment_nonce + the mint route (identity-bound bootstrap to extend for lifecycle-admin seeding).
Design-of-record: ADR 0034 — Complete the base peer-studio (docs/adr/0034-base-peer-studio-control.md), decision D3.
Notes
This is the security-critical root of the trust model → HITL. It carries no UI and is fully unit-testable. The ADR + CONTEXT.md (already authored) ride this slice's PR.
Important
Problem — The control-grant machinery (scopes, state machine, write gate) exists but is dormant and unseeded: no flow mints a
controlgrant, andlifecycle-adminauthority is never established — so a headless peer can never be approved from anywhere. See #1540 for the full design and the independent-peer model.Approach — Seed
lifecycle-adminauthority at Enroll (record the enroller as the target'sauthorityIdentityKey, riding the identity-bound enrollment nonce + Observe bootstrap), and extend the self-owned fast-path (theevaluateObserveBootstrappattern) to mint acontrolgrant on an explicit enable act. Control lands per-session and is never auto-restored.Scope — in: enroll seeding of
lifecycle-admin; self-ownedcontrolissuance; per-session re-arm semantics. · out: the write plane (#1540 slice 2); UI (slice 4); the shared handshake (slice 5).Assumptions — Enroll already establishes bilateral identity + reader-token Observe; both machines are self-owned by one operator.
Warning
Deliberate-review corrections (2026-09-24) — these BIND over any stale text below.
lifecycle-adminauthority is NET-NEW persistence, not a wiring. TodayauthorityIdentityKeyexists only as an injected parameter to the pureisLifecycleAuthoritypredicate (fleet_control_lifecycle.ts:291/303) — no store, no writer, no resolver. This slice must DEFINE: (a) a persisted authority record, (b) a writer invoked atamico fleet enrollrecording the enroller as the target's authority, (c) a resolver answering who holds authority for machine X. The enroll verb (amico-run/fleet_enroll_verb.ts) has no bootstrap/nonce hook today — wiring it is in scope (integration surface, not "unit-testable, no UI").evaluateControlBootstrap, not an extension.evaluateObserveBootstrapexplicitly refuses a control outcome ("there is NO control outcome here — deliberately NOT implemented"). Author a new predicate mirroring its structure; do not "extend" the observe one.management-verifiedmust be a defined predicate. It is a bare boolean set true only in tests today. Name the identity/transport/token check that establishes it, as an AC.fleet_headless_rehydration.ts.controlgrant recordstargetMachineIdand itstokenon the controlling machine, plus a read that resolves a grant bytargetMachineId === <owner>(grants already carrytargetMachineId).Full record: ADR 0034 decision record (D2/D3).
Acceptance Criteria
amico fleet enrollrecords the enroller as the target'slifecycle-adminauthority (theauthorityIdentityKeyis persisted and resolvable afterward).controlgrant via an explicit enable, with no target-side interaction.controlgrant is not auto-restored on rehydration — it lands suspended until an explicit re-enable.lifecycle-adminauthority resolvable from the enrolling machine (the target renders nothing).Testing Decisions
Extend the existing unit suites for
fleet_observe_bootstrap(self-owned vs shared decision),fleet_control_lifecycle(grant issuance/state), andfleet_headless_rehydration(control-never-auto-restored). Add an enroll-seeds-lifecycle-admintest. Reusefleet_two_peer_e2efor the two-machine grant path. Tests assert external behavior (a grant exists/active/suspended; an authority resolves), not internals.Key Decisions
evaluateObserveBootstrap— self-owned + verified management access authorizes the explicit enable; every other case requires approval.lifecycle-adminis not a superset ofcontrol— it mints/revokes/re-admits, it does not itself drive sessions.Constraints & Invariants
Prior Art
Read first (modules):
fleet_observe_bootstrap(the self-owned/shared decision + reciprocal grant issuance),fleet_control_lifecycle(scopes, grant state machine,isLifecycleAuthority),fleet_headless_rehydration(the control-suspended-on-rehydration rule),fleet_enrollment_nonce+ the mint route (identity-bound bootstrap to extend forlifecycle-adminseeding).Source
docs/adr/0034-base-peer-studio-control.md), decision D3.Notes
This is the security-critical root of the trust model → HITL. It carries no UI and is fully unit-testable. The ADR +
CONTEXT.md(already authored) ride this slice's PR.