feat(wake): W3 — cumulative-state digest renderer + non-circular HMAC signer
All checks were successful
ci/woodpecker/pr/ci Pipeline was successful

Builds on the merged W2 store/ack (EPIC #892). Adds A3 (digest.sh) and A5
(sign.sh) under packages/mosaic/framework/tools/wake/, honoring CONVERGED-DESIGN.

A3 — digest.sh (cumulative-state digest renderer), §2.1:
- CUMULATIVE-STATE: renders the FULL unacked set since consumed_seq from the
  durable pending-inbox (state-since-CONSUMED, not an event delta).
- TWO-TIER TRUST: orientation tier (who/lane/board-head + changed-obligation
  list with observed_seq + locators) decides the no-op case with ZERO tool
  calls; actionable tier renders every consequential fact ONLY as a
  CLAIM-TO-VERIFY, point-in-time-at-seq — never auto-actioned.
- HARD LOCATORS: every actionable claim must carry repo+issue#/40-char SHA/
  file:anchor; a missing locator is fail-loud (exit 4, nothing emitted).
- BOUNDING/INJECTION/SECRETS: source free-text is quoted only inside a
  delimited, length-capped, ANSI/bidi/zero-width-stripped untrusted block;
  secret-canary redaction over any inlined content; embeds the W2 ack line.

A5 — sign.sh (non-circular HMAC signer), §2.5:
- wake_id generated INDEPENDENTLY at emit (not derived from, and not a member
  of, the signed field-tuple); wake_mac = HMAC(key, wake_id || agent_identity
  || mission_generation || observed_seq || emit_ts || content_hash) — over
  wake_id PLUS the fields, genuinely non-circular (the MAC is never its own
  input). Fills the `hmac` placeholder W2 left in store entries.
- Key resolved BY NAME from the credential store, never inlined, never echoed;
  no flag accepts key material. Same-uid threat boundary documented; off-uid
  signer named as a future gate.

RED-FIRST tests (test-wake-digest-hmac.sh, wired into test:framework-shell):
cumulative-state, hard-locator fail-loud, two-tier (zero-call orientation +
claim-to-verify), scrub (secret-canary + ANSI/bidi/zero-width), non-circular
HMAC (independent wake_id + tamper-breaks-MAC), key-by-name-never-inline. Each
verified to go RED on a targeted regression. shellcheck clean; operator-agnostic
(XDG/env only). manifest.txt bumped to 0.2.0.

Part of #892

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0158NZqN2n2ymKFeJAZ4GUCb
This commit is contained in:
mosaic-coder
2026-07-25 19:19:10 -05:00
parent dc45eb7c30
commit d3318c5910
5 changed files with 1042 additions and 9 deletions

View File

@@ -25,7 +25,7 @@
"lint": "eslint src",
"typecheck": "tsc --noEmit",
"test": "vitest run --passWithNoTests && pnpm run test:framework-shell",
"test:framework-shell": "python3 src/lease-broker/daemon_deadline_unittest.py && python3 src/lease-broker/normative_fragments_unittest.py && python3 src/lease-broker/receipt_challenge_unittest.py && python3 src/lease-broker/context_recovery_unittest.py && python3 src/lease-broker/recovery_runtime_unittest.py && python3 src/lease-broker/recovery_b1_adversarial_unittest.py && python3 src/lease-broker/framework_skill_portability_unittest.py && python3 src/mutator-gate/runtime_tools_unittest.py && python3 src/mutator-gate/runtime_launch_guard_unittest.py && python3 src/mutator-gate/version_coupling_unittest.py && python3 framework/tools/lease-broker/check-runtime-launches.py --root ../.. && bash framework/tools/codex/test-pr-diff-context.sh && bash framework/tools/qa/test-deps-preflight.sh && bash framework/tools/git/test-pr-review-gitea-comment.sh && bash framework/tools/git/test-pr-review-repo-host-override.sh && bash framework/tools/git/test-ci-queue-wait-branch-absent.sh && bash framework/tools/git/test-git-credential-mosaic.sh && bash framework/tools/git/test-gitea-token-identity.sh && bash framework/tools/_scripts/test-install-ordering-guard.sh && bash framework/tools/tmux/agent-send.test.sh && bash framework/tools/wake/test-wake-store-ack.sh"
"test:framework-shell": "python3 src/lease-broker/daemon_deadline_unittest.py && python3 src/lease-broker/normative_fragments_unittest.py && python3 src/lease-broker/receipt_challenge_unittest.py && python3 src/lease-broker/context_recovery_unittest.py && python3 src/lease-broker/recovery_runtime_unittest.py && python3 src/lease-broker/recovery_b1_adversarial_unittest.py && python3 src/lease-broker/framework_skill_portability_unittest.py && python3 src/mutator-gate/runtime_tools_unittest.py && python3 src/mutator-gate/runtime_launch_guard_unittest.py && python3 src/mutator-gate/version_coupling_unittest.py && python3 framework/tools/lease-broker/check-runtime-launches.py --root ../.. && bash framework/tools/codex/test-pr-diff-context.sh && bash framework/tools/qa/test-deps-preflight.sh && bash framework/tools/git/test-pr-review-gitea-comment.sh && bash framework/tools/git/test-pr-review-repo-host-override.sh && bash framework/tools/git/test-ci-queue-wait-branch-absent.sh && bash framework/tools/git/test-git-credential-mosaic.sh && bash framework/tools/git/test-gitea-token-identity.sh && bash framework/tools/_scripts/test-install-ordering-guard.sh && bash framework/tools/tmux/agent-send.test.sh && bash framework/tools/wake/test-wake-store-ack.sh && bash framework/tools/wake/test-wake-digest-hmac.sh"
},
"dependencies": {
"@mosaicstack/brain": "workspace:*",