feat(worker): secondmate session runner and IMDS blob lane (R2/R3 PR 2) - #263
Merged
Conversation
R2/R3 PR 2 core: bin/fm-secondmate-session.py drives one compartment leg (IMDS/dir blob transport with the session/ namespace refusal inside the transport, chained outbox, content-addressed inbox with durable dedupe, pi turns, child-intent spool sweep, per-leg commit bundling, close/idle/ wall exits). bin/fm-secondmate-spawn.pi-ext.ts is the staged fm_cloud_spawn tool that writes spool intent files only.
Thirteen units drive the real runner against fixture blob directories and a fixture pi: byte-exact canonical reply blobs, chain continuity across legs, chain-tamper refusal, idle/close/wall exits, child-intent round trip and refusals, the session/ namespace boundary (transport unit + attach path), processed-set dedupe, commit bundling with git bundle verify, attach size-check round trip, and the extension/runner static contract.
…equests A captain message that no longer fits an honest pi turn before the wall is deferred (never marked processed) and replays on the next leg; a child brief at the 256KiB bound that cannot fit the framed outbox message refuses that one intent instead of failing the leg. Both behaviors are pinned by new hermetic units.
…ap leg seconds Absorbs the PR #263 adversarial review: - every pi turn now runs with PI_CODING_AGENT_DIR bound to --agent-dir (default /mnt/account/pi-agent, env FM_SECONDMATE_AGENT_DIR); the supervisor's scrubbed environment drops the variable and pi would otherwise root agent state at an empty HOME/.pi/agent - captain text beginning with '-' refuses loudly instead of riding the pi argv: probed pi 0.84.1 rejects a '--' end-of-options separator (Unknown options: --, ...), so the separator path is not available - --leg-seconds refuses above 21600, the pinned supervisor wall ceiling, and the module docstring records the PR 4 monitor contract that supervisor wall_seconds covers leg_seconds plus the finish-leg budget Two new hermetic units (agent-dir default and override observed by the fixture pi; dash refusal with argv non-reach) plus the ceiling refusal assertion and static markers.
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
R2/R3 PR 2 (R2R3-DESIGN.md, section C item 2): the guest-side secondmate session runner and its IMDS blob lane, hermetic-only. No controller, provider, or monitor changes; message-put/message-collect stay in PR 3 and the dispatching monitor in PR 4.
bin/fm-secondmate-session.py- stdlib-only runner invoked as the argv of a legexecuteunder the pinned supervisor's scrubbed environment. One transport class with two backends (imds: IMDS bearer token against the private blob endpoint, x-ms-version 2021-08-06, no client_id since the worker has exactly one user-assigned identity;dir: a fixture directory with identical list/get/put semantics selected by FM_SECONDMATE_BLOB_DIR). Thesession/namespace boundary (design D.3) is enforced as a raise INSIDE the transport, above the backend split.session/out/<seq8>-<sha256>.json, sequence from 1, chain_digest = sha256(prev_chain_hex + content_sha256_hex), genesis previous 64 zeros; the durable tip is re-derived against the store on every start and any gap, reorder, or substitution REFUSES the leg (exit 2, "SECONDMATE SESSION REFUSED: outbox chain is broken..."), never skips or renumbers. The single tolerated divergence is exactly one content-verified entry past the tip (the PUT-then-record crash window).session/in/<sha256>.json, polled by prefix LIST (default 10s, floor 5), deduped by a durable processed-set on the task disk; replays are no-ops. Attach bundlessession/in/attach/<sha256>.bundleare fetched on demand, size-checked against the announcing message before the fetch, thengit fetched into the repo.pi --print --session-id <persisted uuid> --session-dir <task disk>per captain message (the D.1-proven resume shape); pi stdout returns as a chainedfm.secondmate-message/v1reply. A message with no honest room before the wall is deferred, not marked processed, and replays next leg.bin/fm-secondmate-spawn.pi-ext.tsregistersfm_cloud_spawn(kind, brief, model?, effort?)(kind ship|scout) and writes intent FILES to the spool only - no blob or network reach, statically pinned by the suite. The runner sweeps the spool after each turn, validates the closed schema (unknown key or bad kind refuses by name), and emitsfm.secondmate-child-request/v1built from a fixed key set so no home/account/worktree/harness/SKU/repository field can even be expressed, with the parent identity triple and a self_digest over the canonical payload.session/out/bundle-<seq8>-<sha256>.bundle(cap 256MiB) at leg end and onflush, declared {name, sha256, bytes, commits} in the chained leg summary; zero commits declare none. Tip advances only after upload; pending declarations clear only after the summary that carries them.fm.secondmate-leg-summary/v1naming the reason, bundles, and legs_completed.Test evidence
tests/fm-secondmate-session.test.sh(hermetic; registered in test-capabilities.tsv and behavior-test-durations.tsv) drives the REAL runner binary against fixture blob directories and a fixture pi - no runner internals mocked. 16 units, all green (# fm-secondmate-session.test.sh: all assertions passed):git bundle verifypasses against the dispatched base; zero-commit leg declares no bundleMutation proofs (applied transiently, suite rerun, then reverted; clean tree re-verified green after each):
verify_against_storecall removed) -> RED: "not ok - tampered outbox must refuse: expected exit 2, got 0" (this doubles as the positive control that the chain-verification line is load-bearing)_admitreturns early) -> RED: "transport admitted a name outside session/: outcome.bundle"Also green after the change:
tests/test-suite-seal.test.sh,tests/fm-behavior-shards.test.sh(both consume the edited registries), andbin/fm-lint.shon the new test file.Review absorption (2026-08-20 adversarial review)
agent_turnnow setsPI_CODING_AGENT_DIRfrom--agent-dir/ FM_SECONDMATE_AGENT_DIR (default/mnt/account/pi-agent); the supervisor's scrubbed environment drops the variable and pi would otherwise root agent state at an empty$HOME/.pi/agent. Pinned by unit 8 (fixture pi dumps its environment; default and override both asserted).--end-of-options separator (Error: Unknown options: --, --bogus-flag-xyz), so the separator path is unavailable. Implemented the refusal path instead: captain text beginning with-refuses loudly (message text begins with '-' and cannot ride the pi argv) and never reaches the argv. Pinned by unit 9.--leg-secondsrefuses above 21600 (the pinned supervisor MAX_WALL_SECONDS), asserted in the wall unit; the module docstring records the PR 4 monitor contract that supervisorwall_secondsmust cover leg_seconds plus the finish-leg budget (git bundle 600s + blob put 600s beyond the capped 300s margin).Size
1,649 added lines: ~1,010 are the runner (docstring contract included) and ~540 the 14-unit suite; single concern, no split point that would not orphan the tests from the code they pin.
Honest limits
-e, session resume under the account/task disk split) is proven by the D.1 probe, not by this suite; the fixture pi proves the runner's contract with any conforming binary.--print --session-id --session-dir, plus-ewhen an extension is staged); flags like--approveare the dispatching monitor's decision in PR 4.Design reference:
R2R3-DESIGN.mdsections B.1, B.3, B.4, B.5, C item 2, D (with gate results D.1 passed, D.2 half-resolved).