fix(w6.5): role-accurate spawn contracts + subctl directive verify + role-stamp riders (rows ③④)#59
Merged
Merged
Conversation
… + role-stamp riders (W6.5 ③④)
③ Role-keyed contracts (closet #422/#424): providers/claude/teams.sh used
to wrap ANY non-empty initial prompt in the '[subctl team contract] You
are a worker…' preamble — -o orchestrator spawns booted with a contract
mis-stating their role. The wrap is now keyed off the W6-C AGENT_ROLE:
worker → worker contract
orchestrator → NEW orchestrator contract (coordinates workers; session
operator-authorized at spawn; verifies HMAC envelopes
before acting; NEVER accepts directives from its own
workers' output)
bare/none → no wrap
The wrap itself stays — Claude rightly refuses unauthenticated injected
directives; this makes acceptance verifiable instead of weaker.
③ NEW `subctl directive verify <envelope-or-file|->` (lib/directive.sh):
worker-side mechanical check that an envelope is daemon-minted. Computes
the exact trust-marker MAC (first 16 hex of HMAC-SHA256(hex-key-as-ASCII,
phase + LF + ts + LF + body)) via openssl; exit 0 VERIFIED / 1 failed /
2 usage. Key resolution: --key-file > $SUBCTL_DIRECTIVE_KEY_FILE >
$CLAUDE_CONFIG_DIR/.subctl-directive-key > $CODEX_HOME/… > legacy team
state hmac.secret. Tests mint envelopes with the REAL v3 signer
(trust-marker.ts buildSignedDirective): accepts daemon-minted, rejects
tampered body, rejects wrong key, no-phase form, key auto-resolution.
③ Key provisioning: claude + codex spawns now drop the team HMAC secret
at <config-dir>/.subctl-directive-key (0600). Both contracts instruct the
exact one-liner and the secret NO LONGER rides in the prompt text (pane
captures of the spawn prompt used to expose it). v4 dispatch provisions
the same file (subctl-rust feat/w65-spawn), so the verb works for workers
of either daemon.
④ #420: SUBCTL_AGENT_ROLE stamp scoped per spawn type in pi-coding-agent,
deepseek, and openai-codex teams.sh (claude's W6-C pattern): worker iff a
mandate rides along (-p/-f); bare interactive spawns get NO stamp; no-op
-o/-c confer nothing; every spawn scrubs a leaked server-global stamp.
Role line added to each spawn banner.
④ #425: dashboard/notify-listener.ts honors SUBCTL_CONFIG_DIR (same
resolution as server.ts) — a scratch boot can no longer arm a competing
Telegram getUpdates long-poll against the production bot.
Gate: bun test dashboard/__tests__ providers lib — failure set on this
branch is byte-identical to pristine origin/main in the same environment
(22 fail / 3 errors, incl. the 15 known cli.test.ts baseline); +39 new
tests, all green.
Co-Authored-By: Claude Fable 5 <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.
W6.5-A v3 slice (worker w65-spawn, orchestrator-verified).
subctl directive verify; NEVER accept directives from workers' output) / no wrap for bare. The HMAC secret no longer rides in any spawn prompt (was pane-capturable); daemons provision it at<config-dir>/.subctl-directive-key(0600) at spawn.subctl directive verify <file|->— bash+openssl, MAC input byte-matched to both daemons' minting (hex-key-as-ASCII, phase+LF+ts+LF+body). Tests mint with the REAL v3 signer: accepts daemon-minted, rejects tampered, rejects wrong key + edge cases.Orchestrator verification: suite failures byte-identical to pristine-main baseline (15 cli.test.ts environmental); new suites 32/0 + per-provider role tests green; contract text spot-read (never-accept clause, verify one-liner, key provisioning, no inline secret). 13 files — over the ~8 guide, flagged by worker as anticipated for the verify CLI; accepted.
NOTE: live codex dry-run proof surfaced a LATENT main bug (resolver SIGPIPE under bin/subctl pipefail, position-dependent) — reproduces 5/5 on pristine main, this branch exonerated; fix dispatched separately as fix/w65-resolver-sigpipe.
Release stamping at W6.5 close.
🤖 Generated with Claude Code