Skip to content

fix(w6.5): role-accurate spawn contracts + subctl directive verify + role-stamp riders (rows ③④)#59

Merged
webdevtodayjason merged 1 commit into
mainfrom
fix/w65-contracts
Jun 12, 2026
Merged

fix(w6.5): role-accurate spawn contracts + subctl directive verify + role-stamp riders (rows ③④)#59
webdevtodayjason merged 1 commit into
mainfrom
fix/w65-contracts

Conversation

@webdevtodayjason

Copy link
Copy Markdown
Owner

W6.5-A v3 slice (worker w65-spawn, orchestrator-verified).

  • Row ③ contracts: wrap keyed off W6-C role resolution — worker contract / NEW orchestrator contract (verify envelopes via 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.
  • Row ③ verify CLI: 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.
  • Row ④ riders: #420 SUBCTL_AGENT_ROLE scoped per spawn type in pi/deepseek/openai-codex teams.sh (mirrors W6-C claude pattern, per-provider tests); #425 notify-listener honors SUBCTL_CONFIG_DIR (decoy-file test).

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

… + 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>
@webdevtodayjason
webdevtodayjason merged commit 70674c3 into main Jun 12, 2026
@webdevtodayjason
webdevtodayjason deleted the fix/w65-contracts branch June 12, 2026 01:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant