Repository navigation
feat(fleet): native reservation adoption (register.sh honors signed Trackboard reservations) - #13
Merged
Merged
Conversation
…rackboard reservations) When a Claude session starts to fulfil a Trackboard "reservation" (a signed request to create/launch an agent with a chosen name/role/mission/model), the SessionStart hook now adopts it AUTHORITATIVELY on the real host — the on-host counterpart to Trackboard's server-side reconcile task, and what makes the *mission* seed reliable. New `adopt.sh` (sourced by `register.sh` after `reap`) does, on a clean match: - writes the identity overlay `identities/<sid>.json` (the same file Trackboard's roster reads), - seeds the mission host-locally + window-keyed: `GOALSTACK_WINDOW=<sid> goalstack set <mission>`, - records the device slug as `host` in the agent file (read_roster surfaces it), - flips the reservation to `status=adopted` (bound_sid/bound_host/adopted_via=native) and RE-SIGNS it. Security + correctness: - Authenticity: the shared, on-default-unauthenticated `reservations/` dir means a local writer could drop a forged reservation to seed a live agent's goalstack. adopt_reservation honors ONLY reservations whose HMAC `sig` verifies with the per-host key Trackboard mints them with. Cross- language parity is byproduct-proven: bash `jq -cS 'del(.sig)'` + `openssl … -macopt hexkey:` reproduce Trackboard's canonical payload + signature exactly; the hook re-signs after mutating so the signed-only read path keeps surfacing the record. - Multi-device: host slug from `$FLEET_HOST` (never `hostname`); a named-device reservation is adopted only on that device. Exact rid via `$FLEET_RESERVATION` (preferred, unambiguous); the cwd fallback adopts NONE on ambiguity — never a silent guess. - Fail-OPEN + back-compat: missing jq/openssl, no key, no/ambiguous match, or a bad signature → a silent no-op; the agent file is byte-identical to the pre-adoption baseline when nothing is adopted. Forcing function: `selftest-adopt.sh` (hermetic, wired into CI) proves each guarantee BITES with a control that fires — adoption (overlay + mission + flip + re-sign), forgery/ambiguity/wrong-status/ wrong-host all REFUSED, and byte-compatible registration when nothing is adopted. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…servation (adopt interop gate) Folds the load-bearing cross-language proof into PR #13's own CI (this repo is pure bash, so the full round-trip that re-verifies a bash re-signature in Python lives in the trackboard suite). New selftest-adopt.sh check B10: a golden reservation minted by Python with Trackboard's exact signing — json.dumps(record-minus-sig, sort_keys=True, separators=(",",":")) then HMAC-SHA256, under a key DERIVED from a public string (sha256("trackboard-adopt-selftest-golden-v1"), not a real credential) — must be accepted by adopt.sh's `jq -cS` + `openssl` verification. If it is, bash and Python agree on canonicalization; a future jq/openssl drift is caught at CI time without needing Python here. The control (a 1-field corruption, stale sig) must be rejected. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
When a Claude session starts to fulfil a Trackboard reservation (a signed request to create/launch an agent with a chosen name/role/mission/model), the SessionStart hook now adopts it authoritatively on the real host — the on-host counterpart to Trackboard's server-side reconcile task, and what makes the mission seed reliable (it runs on the target host, keyed by the real session id).
New
adopt.sh(sourced byregister.shafterreap) does, on a clean match:identities/<sid>.json(the same file Trackboard's roster reads — survives the heartbeat rewrite by construction),GOALSTACK_WINDOW=<sid> goalstack set <mission>,hostin the agent file (read_rostersurfaces it; the reconcile host-qualifier trusts it),status=adopted(bound_sid/bound_host/adopted_via=native) and re-signs it.Engineering
reservations/is shared + on-default-unauthenticated, so a local writer could drop a forged reservation to seed a live agent's goalstack.adopt_reservationhonors only reservations whose HMACsigverifies with the per-host key Trackboard mints them with. Cross-language parity is byproduct-proven: bashjq -cS 'del(.sig)'reproduces Trackboard's canonical (sorted-key, compact) payload andopenssl … -macopt hexkey:reproduces the exact signature. After mutating the record the hook re-signs it (it holds the key) so Trackboard's signed-only read path keeps surfacing it as adopted.$FLEET_HOST(a launcher/profile env) — neverhostname; a named-device reservation is adopted only on that device. Exact rid via$FLEET_RESERVATION(unambiguous, preferred); the cwd fallback adopts NONE on ambiguity — never a silent guess.jq/openssl, no key (no Trackboard ran on this host), no/ambiguous match, or a bad signature → a silent no-op (the session registers exactly as before; Trackboard's reconcile task is the backstop). When nothing is adopted, the agent file is byte-identical to the pre-adoption baseline (thehostfield appears only on a clean adoption).Verification
selftest-adopt.sh(hermetic, wired into CI) — 13 checks, each with a control that fires:goalstackrecordsGOALSTACK_WINDOW=<sid> set <mission>).$FLEET_RESERVATIONdisambiguates. B7 status gate (areservedone isn't adopted). B8 host qualifier (a named-device reservation needs a matching$FLEET_HOST; control: matching slug adopts + recordsbound_host).host, 9 fields); an adopted one gains exactlyhost(10 fields).--severity=warningclean; SSH-signed; branched off the latestmain(post-attic feat(fleet): commit-attic — work-loss hardening (never lose a committed slice) #12).Pairs with Trackboard D-v2 S4a (server-side reconcile). Composition: patched source → native adoption fires first on the target host (reliable mission); un-patched → the reconcile task adopts name/role/mission remotely. Both write the same overlay + status transition.
🤖 Generated with Claude Code