mirror of
https://github.com/Heretek-AI/heretek-rigs.git
synced 2026-11-07 10:55:57 -10:00
- seat-sandbox.sh: point XDG_CACHE_HOME and GOCACHE at the per-run scratch. The jail binds / read-only, so go build/test died on ~/.cache/go-build (live finding from the fleet-proofs runbook, Refs #91, Refs #12). Red-proof test reproduces the live error on the old wrapper. - Document the single-seat refresh and re-home routes that OpenRig 0.7.5 already ships (rig seat launch --fresh --stop, rig seat set-cwd), which the seat-heal/repair waves used live (Refs #11, Refs #78). - New generated docs/SEAT-WRITE-SCOPES.md (scripts/seat-scopes.py) with a drift test against fleet/fleet.yaml (Refs #78). Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01VjcGdhFQxjHWWV9xxvurqs
87 KiB
87 KiB
Heretek-Rigs Verification & Discovery Log
M0 — Repo scaffold
.gitignorecreated.
M1 — Toolchain / vendor clones — BLOCKED
- Toolchain/vendor clones BLOCKED: shell
permission.rejected. - External paths
/home/john/Projects/Heretek-Crewand/home/john/Projects/openrig-workspace/...permission.rejected. - Cannot run
node/rig/pi/uv. - Cannot run
git log. - Exact blocker error verbatim:
permission.rejected. - Same error survived >3 attempts -> stop per rule 5.
M2 — Secrets — BLOCKED
.env.examplewrite BLOCKED with exact error verbatim:Permission denied: edit(policy blocks.env*files).
M3 — Files created via file tools only
policies,mock-openai.mjs,gate-run.sh,render-seat.py,seed-rig.py,bootstrap-pi-seats.sh,test_render_seat.py,generate-rigs.py,gate-role.sh,verify-rigs.sh,Makefilecreated verbatim fromPROMPT_SPOONFEEDER_OPENCODE_IMPLEMENTATION.mdvia file tools only.
M4 — Schemas / sidecars — MISSING (copy source blocked)
schemas/*.v1.schema.jsonMISSING (needs/home/john/Projects/openrig-workspace/openrig/docs/reference/schemas/copy, blocked).docker-compose.sidecars.ymlMISSING (needs/home/john/Projects/Heretek-Crew/docker-compose.sidecars.ymlcopy, blocked).- Blocker: external-path read
permission.rejected.
M5 — Generation — NOT generated (needs shell + pins)
specs/,rigs/,rosters/,registry/,fleet/skills-lock.jsonNOT generated.- Needs
python3 scripts/generate-rigs.py+ pinnedHeretek-Crew@5ffb1fc. - Vendor clones
obra_superpowers@bb92a77,trailofbits_skills@5c99c03,getsentry_skills@f57ada2,anthropics_skills@dbd4588,vercel-labs_agent-skills@063bee9,openrig-coreskills — all blocked by no-shell + no-external-read. - Same error survived >3 attempts -> stop per rule 5.
M6 — Verification — NOT executed (shell blocked)
verify-rigs.sh, unit tests,audit_loopself-test NOT executed (shell blocked).- Exact blocker error verbatim:
permission.rejected. - Same error survived >3 attempts -> stop per rule 5.
2026-10-19 — Remediation pass (file-tool-only; shell still blocked)
default.shellprobe (pwd; python3 --version; ...) →{"type":"permission.rejected",...}. No commands executed..env.examplewrite →Permission denied: edit(policy blocks.env*; M2 blocker persists).- External read
/home/john/Projects/Heretek-Crew/docker-compose.sidecars.yml→permission.rejected(M4 blocker persists). - Applied fail-closed source fixes (see
REMEDIATION_LOG.md): 11-guardpath_writeinrender-seat.py+ verifier ordering, 7th filepi-permission-config.jsoningenerate-rigs.py, lifecycle/hookschecks,--outputreject, secret-shape allowlist + fleet scan, 8-key proxy + pin/:ro+ network isolation, evaluatorIGNORECASE+ fence-strip + 3 extra self-test vectors, audit-prompt baseUrl/recipe/claim corrections,gate-role.shdocs/AGENTS.md+--outputprobes. - Created
docker-compose.sidecars.ymlbaseline (loopback, pinned, GET-only proxy) and 6schemas/*.v1.schema.jsonbaselines matching generator shapes; originals still need vendoring from blocked checkouts. - Generation + verification STILL REQUIRE shell host:
python3 scripts/generate-rigs.py && ./scripts/verify-rigs.sh --check-only && ./scripts/bootstrap-pi-seats.sh --all --dry-run && python3 ./scripts/audit_loop.py --self-test(all must exit 0; second generate must be diff-clean).
2026-10-19 — Remediation pass per PROMPT_FLEET_AUDIT_REMEDIATION.md (file-tool-only)
default.shellprobe (pwd; git rev-parse --show-toplevel; ls) →{"type":"permission.rejected","message":"This non-interactive run cannot ask the user for permission..."}(1 attempt, no retries).- External reads
/home/john/Projects/Heretek-Crew,/home/john/Projects/openrig-workspace/openrig→permission.rejected(M4/M5 blockers persist). python3 scripts/generate-rigs.py,./scripts/verify-rigs.sh --check-only,./scripts/bootstrap-pi-seats.sh --all --dry-run,python3 ./scripts/audit_loop.py --self-test→ NOT RUN (same blocker). Second-run idempotency UNTESTABLE.- Fail-closed verifier hardening applied (see
REMEDIATION_LOG.md2026-10-19 entry):rig.yamlreserved/secret-name scan (HR-4.4), per-seatmcp["*"]:deny+ bound-server-only assert (HR-5.5),Makefileguard-profiles coverage (HR-7.3), 8-deliverable placeholder scan (HR-8.4). No check weakened; 18×builtin:locked,*..*deny-last, triple-deny,!cattemplates, loopback/pinned sidecars preserved. - P0 generation findings STILL OPEN (blocked here); shell host must run gate until green, then
scripts/audit_loop.pyspawns next triad audit.
2026-10-19 — Remediation pass per PROMPT_FLEET_AUDIT_REMEDIATION.md (file-tool-only)
default.shellprobes (pwd; ls -lathenpython3 ./scripts/generate-rigs.py && ./scripts/verify-rigs.sh --check-only) → each{"type":"permission.rejected","message":"This non-interactive run cannot ask the user for permission..."}(2 attempts, 0 blind retries; stop per hard rule 4).python3 scripts/generate-rigs.py,./scripts/verify-rigs.sh --check-only,./scripts/bootstrap-pi-seats.sh --all --dry-run,python3 ./scripts/audit_loop.py --self-test→ NOT RUN (same blocker). Second-run idempotency UNTESTABLE.- Fail-closed hardening applied (see
REMEDIATION_LOG.mdlatest entry): generator float + ASCII-only JCS die (HR-3.2), verifier ASCII-only assert +SYNTHETIC-warn/CI=trueforbid (HR-3.2/HR-3.3), seed passthrough + idempotency wiring + guard-message asserts (HR-4.2/HR-8.1/HR-7.3). No check weakened; 20×builtin:locked,*..*deny-last, triple-deny,!cattemplates, loopback/pinned sidecars preserved. - P0 generation findings STILL OPEN (blocked here); shell host must run gate until green, then
scripts/audit_loop.pyspawns next triad audit.
2026-10-19 — Remediation pass per PROMPT_FLEET_AUDIT_REMEDIATION.md (file-tool-only, current-findings sweep)
default.shellprobe (pwd; git rev-parse --show-toplevel; ls) →{"type":"permission.rejected","message":"This non-interactive run cannot ask the user for permission, so the request was rejected. Continue without this action."}(1 attempt, 0 blind retries; stop per hard rule 4 well before 3).python3 scripts/generate-rigs.py,./scripts/verify-rigs.sh --check-only,./scripts/bootstrap-pi-seats.sh --all --dry-run,python3 ./scripts/audit_loop.py --self-test→ NOT RUN (same blocker). Second-run idempotency UNTESTABLE.- Reproduction via file tools:
Glob specs|rigs|registry|rosters|**/skills-lock*→ allNo files found;.scratch/holds onlyaudit-loop-logs/;fleet.yaml20×builtin:locked, 15 pods + 51 member_fragments explicit;identity-vectors.json+ 6/6 schemas present; all generator/verifier/renderer/gate hardenings re-verified present byRead/Grep(seeREMEDIATION_LOG.mdlatest entry).generate-rigs.py:939 guidance_mergeconfirmed as legitimatetoldFilesculture delivery, not anagent.yamlstartup file. - No code change this pass (source already hardened; no
Caught? = Nosabotage to trigger hard rule 2). No check weakened; 20×builtin:locked,*..*deny-last, triple-deny,!cattemplates, loopback/pinned sidecars preserved. - P0 generation findings STILL OPEN (blocked here); shell host must run gate until green, then
scripts/audit_loop.pyspawns next triad audit.
2026-10-19 — Remediation pass per PROMPT_FLEET_AUDIT_REMEDIATION.md (current-findings sweep, 4 source hardenings)
default.shellprobes (pwdprobe +python3 scripts/generate-rigs.pyprobe + gate batchverify-rigs.sh --check-only && bootstrap-pi-seats.sh --all --dry-run && audit_loop.py --self-test) → each{"type":"permission.rejected","message":"This non-interactive run cannot ask the user for permission, so the request was rejected. Continue without this action."}(3 attempts, 0 blind retries; stop per hard rule 4 at threshold, no blind retries).python3 scripts/generate-rigs.py,./scripts/verify-rigs.sh --check-only,./scripts/bootstrap-pi-seats.sh --all --dry-run,python3 ./scripts/audit_loop.py --self-test→ NOT RUN (same blocker). Second-run idempotency UNTESTABLE.- Fail-closed source hardenings applied (see
REMEDIATION_LOG.mdlatest entry):docs/OPENRIG_MUSE_GO_ARCHITECTURE.mdJCS doc fix (HR-3.2), verifierSYNTHETIC-ack-gated fail unlessHERETEK_ALLOW_SYNTHETIC=1(HR-3.3),gate-role.sh+8 deny probes for.git/hooks/.pi/.agents/*/secrets/*/*.url/*.user/read-../code_rewrite(HR-5.2), compose HR-7.3 coexistence matrix + verifiersidecars-up -> guard-profileswiring assert. No check weakened; 20×builtin:locked,*..*deny-last, triple-deny,!cattemplates, loopback/pinned sidecars preserved. - P0 generation findings STILL OPEN (blocked here); shell host must run
python3 scripts/generate-rigs.py && ./scripts/verify-rigs.sh --check-only && ./scripts/bootstrap-pi-seats.sh --all --dry-run && python3 ./scripts/audit_loop.py --self-testuntil green, thenscripts/audit_loop.pyspawns next triad audit.
2026-10-19 — Remediation pass per PROMPT_FLEET_AUDIT_REMEDIATION.md (current-findings sweep, verify-only)
default.shellprobes (pwd; git rev-parse --show-toplevel; ls -la, thenpython3 scripts/generate-rigs.py && ./scripts/verify-rigs.sh --check-onlygate) → each{"type":"permission.rejected","message":"This non-interactive run cannot ask the user for permission, so the request was rejected. Continue without this action."}(2 attempts, 0 blind retries; stop per hard rule 4 well before 3).python3 scripts/generate-rigs.py,./scripts/verify-rigs.sh --check-only,./scripts/bootstrap-pi-seats.sh --all --dry-run,python3 ./scripts/audit_loop.py --self-test→ NOT RUN (same blocker). Second-run idempotency UNTESTABLE.- Reproduction via file tools:
Glob specs|rigs|registry|rosters|**/skills-lock*→ allNo files found;fleet.yaml20×builtin:locked, zeroyolo/open/guidance_merge/0.0.0.0/:latest, zero reserved-name literals;identity-vectors.json+ 6/6 schemas present; docjcs_canonicalize()citation +gate-role.sh:59-75extended corpus + all generator/verifier/renderer hardenings re-verified present byRead/Grep(seeREMEDIATION_LOG.mdlatest entry). Sabotage table: 12×NOT RUN, zeroCaught? = No→ hard rule 2 not triggered. - No code change this pass (source already hardened; P0s are generation-blocked, P1-P3 execution halves need shell/Docker/network/
pi). No check weakened; 20×builtin:locked,*..*deny-last, triple-deny,!cattemplates, loopback/pinned sidecars preserved. - P0 generation findings STILL OPEN (blocked here); shell host must run the gate until green, then
scripts/audit_loop.pyspawns next triad audit.
2026-10-19 — Remediation pass per PROMPT_FLEET_AUDIT_REMEDIATION.md (current-findings sweep, verify-only)
default.shellprobes (pwd; git rev-parse --show-toplevel; ls -la; python3 --version, thenpython3 ./scripts/generate-rigs.py && ./scripts/verify-rigs.sh --check-onlygate batch) → each{"type":"permission.rejected","message":"This non-interactive run cannot ask the user for permission, so the request was rejected. Continue without this action."}(2 attempts, 0 blind retries; stop per hard rule 4 well before 3).python3 scripts/generate-rigs.py,./scripts/verify-rigs.sh --check-only,./scripts/bootstrap-pi-seats.sh --all --dry-run,python3 ./scripts/audit_loop.py --self-test→ NOT RUN (same blocker). Second-run idempotency UNTESTABLE.- Reproduction via file tools:
Glob specs|rigs|registry|rosters|**/skills-lock*→ allNo files found;.scratch/holds onlyaudit-loop-logs/; 6/6 schemas present;identity-vectors.json:1-31present;.gitignore:1-8ignores only deps (absence is real HEAD-state defect);fleet.yaml20×builtin:locked, zeroyolo/open/guidance_merge, zero active0.0.0.0/:latest;--outputdie-guards + triple-deny +*..*deny-last + 18-toggle proxy + idempotent wiring + evaluator hardening all re-verified present byRead/Grep(seeREMEDIATION_LOG.mdlatest entry). Sabotage table: 12×NOT RUN/UNVERIFIABLE, zeroCaught? = No→ hard rule 2 not triggered. - No code change this pass (source already hardened; P0s are generation-blocked, P1-P3 execution halves need shell/Docker/network/
pi). No check weakened; 20×builtin:locked,*..*deny-last, triple-deny,!cattemplates, loopback/pinned sidecars preserved. - P0 generation findings STILL OPEN (blocked here); shell host must run the gate until green, then
scripts/audit_loop.pyspawns next triad audit.
2026-10-19 — Remediation pass per PROMPT_FLEET_AUDIT_REMEDIATION.md (486-line findings sweep, verify-only)
default.shellprobes (pwd; git rev-parse --show-toplevel, thenpython3 ./scripts/generate-rigs.py, thenecho blocked) → each{"type":"permission.rejected","message":"This non-interactive run cannot ask the user for permission, so the request was rejected. Continue without this action."}(3 attempts, 0 blind retries; stop per hard rule 4).python3 scripts/generate-rigs.py,./scripts/verify-rigs.sh --check-only,./scripts/bootstrap-pi-seats.sh --all --dry-run,python3 ./scripts/audit_loop.py --self-test→ NOT RUN (same blocker). Second-run idempotency UNTESTABLE.- Reproduction via file tools:
Glob specs|rigs/**/*→No files found;Grep builtin:locked fleet/→ 20 hits;Grep *..*|code_rewrite|guidance_merge|builtin:yolo|0.0.0.0|:latest→ no active violations; all generator/verifier/renderer hardenings re-verified present (seeREMEDIATION_LOG.mdlatest entry). Sabotage table: 12×NOT RUN, zeroCaught? = No→ hard rule 2 not triggered. - No code change this pass (source hardened; P0s generation-blocked, P1-P3 execution halves need shell/Docker/network/
pi). No check weakened. - P0 generation findings STILL OPEN (blocked here); shell host must run gate until green, then
scripts/audit_loop.pyspawns next triad audit.
2026-10-19 — Shell-host remediation pass (FULL GATE GREEN, 4 source fixes)
- Resolved M0 blocker: cloned 5 vendor pins at exact SHAs (
obra_superpowers@bb92a77,trailofbits_skills@5c99c03,getsentry_skills@f57ada2,anthropics_skills@dbd4588,vercel-labs_agent-skills@063bee9);Heretek-Crew@0b41346(allowed),openrig-coreskills present; installed pinned[email protected]/[email protected]+pi-packages([email protected],[email protected],[email protected]);pyyamlviapip --user.HERETEK_RIGS_ALLOW_DIRTY=1(onlyloop.logdirty; realHEADprovenance). - Source fixes (fail-closed): (1)
verify-rigs.sh—runtime/mcp.jsonstub floor replaced by binding-exactness (zero-server roles must render exactly{}); (2)gate-role.shuv fallback argv forwarding (+ sys.argv); (3)gate-role.sh expect()|| true(no silent abort); (4)render-seat.pypathmap gained the 10-guard dot-dir block (first live corpus run caught real.pi/+.agents/read allows) + verifier asserts + exact-order unit test. - Live evidence: gate 22/0;
rig spec validate8/8;rig agent validate51/51;preflight8/8 ready;bundle check8/8 rc=0 zero fails;gate-role.sh23/23 × appsec + exec-director; sabotage 14/14 caught; compose config 8×127.0.0.1 + 10 pinned images; JCS independent MATCH; strict bootstrap fail (rc 2) + 0600-probe dry-run 54 seats (rc 0) + REAL bootstrap 54 seats/324 files all-0600 with pinned endpoint;audit_loop.py --self-testPASSED;--check-idempotentbyte-identical. Daemon stopped,/tmpscratch cleaned. Full per-HR mapping inREMEDIATION_LOG.mdlatest entry. - Residual (not claimed): registry liveness (
npm view/pip index), live proxy GET-denial, remaining 49-role corpus, fleet-edit die micro-proof, upstream vectors diff. Generated trees on disk untracked; 4 tracked source files modified.AUDIT_REPORT_FINDINGS.mduntouched for next triad audit.
2026-10-19 — Remediation pass per PROMPT_FLEET_AUDIT_REMEDIATION.md (341-line 11-finding sweep, regen-blocked)
default.shellprobes (pwd; git rev-parse --show-toplevel; ls scripts/,python3 ./scripts/generate-rigs.py,./scripts/verify-rigs.sh --check-only) → each{"type":"permission.rejected","message":"This non-interactive run cannot ask the user for permission, so the request was rejected. Continue without this action."}(3 attempts, 0 blind retries; stopped per hard rule 4, no further shell calls).python3 scripts/generate-rigs.py,./scripts/verify-rigs.sh --check-only,./scripts/bootstrap-pi-seats.sh --all --dry-run,python3 ./scripts/audit_loop.py --self-test→ NOT RUN (same blocker). Second-run idempotency UNTESTABLE.- Reproduction via file tools:
specs/.../policy-enforcement.json:22-35bash ends atgit show --stat*(zero terminal denies) vsrender-seat.py:380-381emits all five LAST vsverify-rigs.sh:390-400demands them LAST → clean tree fails own gate by construction (HR-5.5, breaks 8.2/8.3);Grep *--output*zero inspecs//rigs/; 20builtin:lockedintact; all other P2/P3 static halves hold. NoCaught? = Nosabotage → hard rule 2 not triggered. - No source change this pass (generator/renderer/verifier already correct and agreeing; leaves NOT hand-edited per hard rule 1 — would desync digests). Shell host MUST run
python3 scripts/generate-rigs.pyFIRST then the gate until green. Full per-HR mapping inREMEDIATION_LOG.mdlatest entry.
2026-10-19 — Remediation pass per PROMPT_FLEET_AUDIT_REMEDIATION.md (309-line 10-finding sweep, verify-only, shell-blocked)
default.shell3 attempts (hard-rule-4 limit, 0 blind retries), all{"type":"permission.rejected","message":"This non-interactive run cannot ask the user for permission, so the request was rejected. Continue without this action."}: (1)pwd+git rev-parse+git statusprobe, (2)python3 ./scripts/generate-rigs.py, (3)./scripts/verify-rigs.sh --check-only. NOTE: repo-rootopencode.jsonallowlist (prior GREEN pass) still present but this seat rejects every shell call anyway; permission config left untouched (no self-authorizing).python3 scripts/generate-rigs.py,./scripts/verify-rigs.sh --check-only,./scripts/bootstrap-pi-seats.sh --all --dry-run,python3 ./scripts/audit_loop.py --self-test→ NOT RUN (same blocker). Second-run idempotency UNTESTABLE.- Reproduction via file tools: 51
specs/.../agent.yaml+ 8rigs/*/rig.yaml+ 15 omni pods + 51 omni members + registry/roster/skills all present on disk; exec-directorpolicy-enforcement.json:35-39+pi-permission-config.json:28carry all five terminal denies LAST (prior HR-5.5 stale-tree GONE, audit confirms 102 hits); shebangs on all 9 scripts;Makefileon explicitbash/python3; verifier exec-bit self-gate:68-84present; zero..inagent_ref;symlinks=False×4;secret_oktriple defense +!echo Bearercommand-backed secrets;semgrep: run-failed-here+radare2: not-runhonestly labeled; make+wrapper co-schedule guard + documented raw-compose bypass. Sabotage table: 12×NOT RUN/UNKNOWN, zeroCaught? = No→ hard rule 2 not triggered. - No source change this pass (all source halves already hardened by prior passes; remaining deltas are live execution only; P3s correctly capped). No check weakened;
builtin:locked,*..*deny-last, triple-deny,!cattemplates, loopback/pinned sidecars preserved. - 1× P1 (HR-8.2 exec-bit: index-bit half UNVERIFIABLE) + 3× P2 (HR-1.1 tracking, HR-2.5 live check, HR-ENV seat policy) STILL OPEN — BLOCKED HERE; 6× P3 backlog/disclosure notes. Shell host must run the gate until green, then
scripts/audit_loop.pyspawns next triad audit. Full per-HR mapping inREMEDIATION_LOG.mdlatest entry.
2026-10-19 — Remediation pass per PROMPT_FLEET_AUDIT_REMEDIATION.md (375-line 12-finding sweep — HR-5.5-enforcement-gap + HR-5.2-corpus + HR-6.2-stale-pins hardened)
default.shell3 attempts (hard-rule-4 limit, 0 blind retries), all{"type":"permission.rejected","message":"This non-interactive run cannot ask the user for permission, so the request was rejected. Continue without this action."}: (1)pwd, (2)python3 ./scripts/generate-rigs.py, (3)./scripts/verify-rigs.sh --check-only. Permission config left untouched (no self-authorizing).python3 scripts/generate-rigs.py,./scripts/verify-rigs.sh --check-only,./scripts/bootstrap-pi-seats.sh --all --dry-run,python3 ./scripts/audit_loop.py --self-test→ NOT RUN (same blocker). Second-run idempotency UNTESTABLE.- Reproduction via file tools: 51
specs/.../agent.yaml(glob), 8rigs/*/rig.yaml(glob), 51 omni members (glob), exec-directorpolicy-enforcement.json:22-40carries 5 terminal denies (pre-fix tree; post-fix source emits 10);grepconfirms zeropi-subagents/[email protected]infleet//specs//rigs//scripts/;gemini/osint_ecosystem_report.md:40,42ADOPTs rejected packages (stale pre-fix);gate-role.sh:43-80corpus subset confirmed. Sabotage table: 12×NOT RUN/UNKNOWN, zeroCaught? = No→ hard rule 2 not triggered (proactive coverage added anyway). - Source fixes this pass (fail-closed, minimal):
scripts/render-seat.pyterminal denies 5 → 10 (*&*, backtick,*$*,*(*,*)*LAST + newline documented as generation-ban + Pi-decomposition);scripts/verify-rigs.shV1 asserts + order check → 10 + new shipped-surfacepi-subagents/[email protected]ban (self-excluded);tests/test_render_seat.pyasserts → 10;scripts/gate-role.sh+4 bash chaining probes (&,$(), backtick, newline) +7 read probes (./-traversal,.env.production,*.pem,fleet/*,scripts/*,*/.git/*);gemini/osint_ecosystem_report.mdRETIRED banner +gemini/RETIRED.md+claude/RETIRED.md. No check weakened;builtin:locked,*..*deny-last, triple-deny,!cat, loopback/pinned sidecars preserved. - P1 exec-bit + P2 tracking/live/process + P3 backlog carries BLOCKED HERE (seat policy); 3 NEW findings HARDENED in source, live hostile-corpus + regen proof pending shell host. Shell host MUST run
python3 scripts/generate-rigs.pyFIRST (51 permission configs + digests change), then the gate until green. Full per-HR mapping inREMEDIATION_LOG.mdlatest entry.
2026-10-19 — Remediation pass per PROMPT_FLEET_AUDIT_REMEDIATION.md (367-line 14-finding sweep — HR-5.5-stale-committed-configs P1)
default.shell4 attempts (hard-rule-4 limit exceeded, 0 blind retries), all{"type":"permission.rejected","message":"This non-interactive run cannot ask the user for permission, so the request was rejected. Continue without this action."}: (1)pwd; git rev-parse; ls, (2)python3 scripts/generate-rigs.py, (3)bash scripts/verify-rigs.sh --check-only, (4)python3 scripts/audit_loop.py --self-test. Stopped, no blind retries. Exact commands + verbatim outputs inREMEDIATION_LOG.mdlatest entry.python3 scripts/generate-rigs.py,./scripts/verify-rigs.sh --check-only,./scripts/bootstrap-pi-seats.sh --all --dry-run,python3 ./scripts/audit_loop.py --self-test→ NOT RUN (same blocker). Second-run idempotency UNTESTABLE.- Reproduction via file tools:
Grep *&* specs/agents→ No matches; committedpolicy-enforcement.json:35-39+pi-permission-config.jsoncarry 5 denies vsrender-seat.py:387-399emitting andverify-rigs.sh:395-403demanding 10 → clean checkout red (HR-5.5-stale P1). Mode bits /git ls-files/find -type l/ live probes UNVERIFIABLE (same blocker). Sabotage table: 12× NOT RUN/UNKNOWN, zeroCaught? = No→ hard rule 2 not triggered. - Source fix this pass (fail-closed, minimal):
PROMPT_ADVERSARIAL_FLEET_AUDIT.md:133Claim 5.5 now lists all 10 terminal denies (was 5; closes docs-precision debt noted in cross-examination). Generator/renderer/verifier/tests already agreed; generated leaves NOT hand-edited per hard rule 1 (would desync digests). No check weakened; 18×builtin:locked,*..*deny-last, triple-deny,!cat, loopback/pinned sidecars preserved. - P1 stale-tree + P1 exec-bit + P2 tracking/live/process + P3 backlog carries BLOCKED HERE (seat policy). Shell host MUST run
python3 scripts/generate-rigs.pyFIRST (102-file deny-additive diff + digests), review, commit, then./scripts/verify-rigs.sh --check-only && ./scripts/bootstrap-pi-seats.sh --all --dry-run && python3 ./scripts/audit_loop.py --self-testuntil green + second generate zerogit diff.AUDIT_REPORT_FINDINGS.mduntouched.
2026-10-19 — Remediation pass per PROMPT_FLEET_AUDIT_REMEDIATION.md (154-line 3-finding sweep — HR-7.3 P2 exact-set, HR-2.1 P3 upstream anchor, HR-6.1 P3 subagent sibling)
default.shell4 attempts: (1)pwd && git rev-parseprobe →permission.rejected; (2) full gate chain → EXECUTED (generator parsedfleet/cleanly, exited 2 on fail-closed dirty-checkout refusal); (3)+(4)HERETEK_RIGS_ALLOW_DIRTY=1 python3 scripts/generate-rigs.py→permission.rejected×2. Hard-rule-4 stop (3 same-error rejections, 0 blind retries). Exact commands + verbatim outputs inREMEDIATION_LOG.mdlatest entry.- Reproduction via file tools (
read/glob/grep): HR-7.3 membership-only gate vs exclusive compose (gap CONFIRMED, coverage-only); HR-2.1 3-local-copies + locally-refreshed hash, zero upstream bytes (gap CONFIRMED); HR-6.1 REQUIREDsuperpowers:subagent-driven-developmentrefs inwriting-plans:59,201+executing-plansSKILL/scripts vs zero lock/disk hits, vendor source present atbb92a77(gap CONFIRMED). Claim Ledger 30× UNVERIFIABLE + Sabotage 12× NOT RUN (no live runtime here); zeroCaught? = No→ rule 2 reactive check not triggered (exact-set + sibling-ref + tarball-anchor coverage added proactively). - Source fixes (fail-closed, minimal; NO generated leaves hand-edited per hard rule 1):
verify-rigs.shHR-7.3 exact network sets (ghidra/radare2/sonarqube={heretek-devsec},docker-android={heretek-mobile}) + HR-2.1upstream_tarball.tarball_sha25664-hex-or-fail (+tgz cross-check) + HR-6.1 62→63 count + REQUIRED/../<id>/scripts/sibling-resolution gate (no false positives:refocusing/scripts/exists);generate-rigs.pyupstream-tarball attestation (never derived from local bytes; idempotent) + docstring 62→63;schemas/rigspec-keys.pinned.jsonupstream_tarballplaceholder + humannpm packrecipe;fleet/fleet.yamlbindssubagent-driven-developmenttoproduct-director+system-architect; audit prompt counts/7.3 wording aligned (62→63, exact-set + sonarqube). No check weakened; 18×builtin:locked,*..*deny-last, triple-deny,!cat, loopback/pinned sidecars preserved. - Gate intentionally red on current disk (HR-2.1 placeholder anchor + HR-6.1 stale artifacts fail closed BY DESIGN); HR-7.3 check passes on current compose. Shell host MUST:
npm pack @openrig/[email protected]→ record tarball SHA (or drop tgz inschemas/) →HERETEK_RIGS_ALLOW_DIRTY=1 python3 scripts/generate-rigs.py(expect63 shared skills) → full gate +--check-idempotentgreen → dual-home + 3-copy-edit sabotage flips → commit →audit_loop.pyspawns next triad audit. Full per-HR mapping inREMEDIATION_LOG.mdlatest entry.
2026-10-19 — Remediation pass per PROMPT_FLEET_AUDIT_REMEDIATION.md (113-line 2-finding P1 sweep: HR-6.1 + HR-2.1)
default.shellintermittent: (1) initial probe →permission.rejected; (2)python3 ./scripts/generate-rigs.py && ./scripts/verify-rigs.sh --check-only→ EXECUTED, generator refused fail-closederror: refusing to bake provenance on a dirty checkout (commit or stash first, or set HERETEK_RIGS_ALLOW_DIRTY=1 for dev regen)exit 2 (leaves untouched); (3)git statusprobe →permission.rejected; (4)HERETEK_RIGS_ALLOW_DIRTY=1 python3 ./scripts/generate-rigs.py→permission.rejected. Hard-rule-4 stop TRIGGERED (3permission.rejectedon same error, 0 blind retries). Full verbatim inREMEDIATION_LOG.mdlatest entry.- Reproduction via file tools: HR-6.1 fleet binds at
fleet.yaml:2860,3359, vendor source.scratch/vendor/obra_superpowers/skills/subagent-driven-development/(SKILL.md+scripts/+ 3 prompts) present, but lock/disk/_shared/agent.yamlstale at 62 with zero sibling hits vs verifier expecting 63 + sibling resolution → red by design; HR-2.1tarball_sha256: PENDING_SHELL_HOST_REFRESH, no tgz, gate 64-hex-or-fail → red by design. Sabotage 12× NOT RUN, zeroCaught? = No→ rule 2 not triggered. - No source change this pass (canonical fix already landed; hand-editing leaves or hand-filling the tarball hash forbidden by hard rules 1/3). No check weakened. Shell host MUST commit/stash inherited dirt, record tarball SHA, regen (expect 63 skills), green the full gate + idempotence, then
audit_loop.pyspawns next triad audit.
2026-10-19 — Remediation pass per PROMPT_FLEET_AUDIT_REMEDIATION.md (108-line 2-finding sweep: HR-2.1 P1 + HR-6.1 P2)
default.shell1 attempt (pwd; git rev-parse --show-toplevel; ls -laprobe) →{"type":"permission.rejected","message":"This non-interactive run cannot ask the user for permission, so the request was rejected. Continue without this action."}(0 blind retries; stopped well before hard rule 4 limit of 3).python3 scripts/generate-rigs.py,./scripts/verify-rigs.sh --check-only,./scripts/bootstrap-pi-seats.sh --all --dry-run,python3 ./scripts/audit_loop.py --self-test→ NOT RUN. Second-run idempotency UNTESTABLE.- Code Mode
executenetwork probe (not a gate substitute): npm metadata 200 (@openrig/[email protected]tarball URL live), tarballHEAD200,GETbody viares.text()len 6732219 (text-decoded, not byte-faithful);arrayBuffer/blobunavailable so byte-faithfulsha256sumUNCOMPUTABLE here — no hash recorded. - Reproduction via file tools: HR-2.1
pinned.json:12placeholder + gate:183-18664-hex-or-fail + no tgz (REPRODUCED); HR-6.1 62 dirs / zero lock hits vs 2 fleet bindings (:2860,:3359) + 5+2 vendored REQUIRED/script refs + vendor source present + verifier 63-count/sibling gates (REPRODUCED). Sabotage 12× NOT RUN, zeroCaught? = No→ rule 2 not triggered. - No source change this pass (canonical bindings + gates + attestation already landed; hand-filling the hash or hand-copying leaves forbidden by hard rules 1/3). No check weakened. Shell host MUST record the tarball SHA, run
python3 scripts/generate-rigs.py(expect 63 skills), green the full gate + idempotence, thenaudit_loop.pyspawns the next triad audit. Full per-HR mapping inREMEDIATION_LOG.mdlatest entry.
2026-10-19 — Remediation pass per PROMPT_FLEET_AUDIT_REMEDIATION.md (135-line 4-finding sweep: HR-2.1 P1 + HR-6.1 P2 + HR-5.5-superset P2 + HR-5.5-patch P3)
default.shell4 attempts, 0 blind retries (stopped per hard rule 4 — samepermission.rejectederror, no further shell calls): (1)pwd; git rev-parse --show-toplevel; echo SHELL_OKprobe →permission.rejected; (2) full gate chainpython3 ./scripts/generate-rigs.py && ./scripts/verify-rigs.sh --check-only && ./scripts/bootstrap-pi-seats.sh --all --dry-run && python3 ./scripts/audit_loop.py --self-test→ EXECUTED once, generator refused fail-closederror: refusing to bake provenance on a dirty checkout (commit or stash first, or set HERETEK_RIGS_ALLOW_DIRTY=1 for dev regen)exit 2 (leaves untouched; dirt is this pass's own source edits); (3)git status --porcelainprobe →permission.rejected; (4)npm pack @openrig/[email protected] --dry-run→permission.rejected(network pack untestable; Code Mode text-fetch precedent stands — byte-faithful SHA UNCOMPUTABLE here).- Reproduction via file tools: HR-2.1
pinned.json:10-14placeholder + gate:183-18664-hex-or-fail +Glob schemas/openrig-cli-0.6.11.tgz→ absent (REPRODUCED); HR-6.1 62*/SKILL.md/ zero locksubagenthits vs fleet binds:2860,:3359+ executing-plans refs:53,60,121,126,236+ vendorskills/subagent-driven-development/(SKILL.md+scripts/+ 3 prompts) present (REPRODUCED); HR-5.5-superset:559-575declared-only vs:534-539mcp-only +:481rendered↔rendered +:1151-1157no re-run (REPRODUCED); HR-5.5-patchgit log --oneline -pmatching allow:24-27with none of the 10 terminal denies matching-p(REPRODUCED). Sabotage 12× NOT RUN at audit time, zeroCaught? = No→ hard rule 2 not triggered (new checks below are finding-remediation, not rule-2 reactive). - Source fixes this pass (fail-closed, minimal; NO generated leaves hand-edited per hard rule 1 —
specs//rigs/still carry the 10-deny set + 62 skills, so the gate stays red BY DESIGN until a shell host regens):render-seat.py:387-414+4 terminal patch denies (* -p*,*--patch*,*--full-diff*,*--textconv*) LAST with residual doc;verify-rigs.shV1 subset check (rendered bash/path_write allows ⊆ fleet-declared) + 10→14 terminal asserts (_TERMINAL_BASH_DENIES, presence + order) +:1081-1089renderer-emit asserts;gate-role.shcanaryfleet/fleet.yamlcommit + 2 must-deny patch probes + 1 anti-over-block allow probe;tests/test_render_seat.pyasserts → 14;PROMPT_ADVERSARIAL_FLEET_AUDIT.md:133claim lists 14 denies + subset clause.Grepfleetbash_allow→ zero-p/--patch/--textconv/--full-diffsubstrings (clean regen unaffected). No check weakened; 20×builtin:locked,*..*deny-last, triple-deny,!cat, loopback/pinned sidecars preserved. - HR-2.1 + HR-6.1 STILL OPEN — BLOCKED HERE (need networked shell:
npm pack→ record SHA → commit/stash orALLOW_DIRTY=1regen expecting 63 skills + 14 denies + refreshed digests → full gate + idempotence green).AUDIT_REPORT_FINDINGS.mduntouched;audit_loop.pyspawns next triad audit after green. Full per-HR mapping inREMEDIATION_LOG.mdlatest entry.
2026-10-20 — Remediation pass per PROMPT_FLEET_AUDIT_REMEDIATION.md (2-finding P3 sweep: HR-6.1-using-superpowers-prose-ref + HR-5.5-tab-p-suffix-gap)
default.shell2 attempts, 0 blind retries (stopped well before hard rule 4 limit of 3 — samepermission.rejectederror class, no further shell calls): (1)python3 ./scripts/generate-rigs.py→{"type":"permission.rejected","message":"This non-interactive run cannot ask the user for permission, so the request was rejected. Continue without this action."}; (2)trueprobe → samepermission.rejected.python3 scripts/generate-rigs.py,./scripts/verify-rigs.sh --check-only,./scripts/bootstrap-pi-seats.sh --all --dry-run,python3 ./scripts/audit_loop.py --self-test→ NOT RUN. Second-run idempotency UNTESTABLE.- Reproduction via file tools: HR-6.1
executing-plans/SKILL.md:50`../using-superpowers/references/`vs zerousing-superpowers*dirs/lock hits, vendor source.scratch/vendor/obra_superpowers/skills/using-superpowers/(SKILL.md+references/inclpi-tools.md) present, gate:337-356blind to../<id>/references/shape (REPRODUCED); HR-5.5* -p*space-anchored +render-seat.py:362ban missing\t+gate-role.sh:69-702/4 probes +verify-rigs.sh:565-567sortedness-only order gate (REPRODUCED). Sabotage table 12× UNVERIFIABLE/NOT RUN, zeroCaught? = No→ rule 2 not triggered (new sibling-doc-ref + tab-deny + terminality coverage added proactively). - Source fixes (fail-closed, minimal; NO generated leaves hand-edited per hard rule 1 — disk still carries 63 skills / 14 denies, so the gate stays red BY DESIGN until a shell host regens):
fleet/fleet.yamlsystem-architectshared:+=using-superpowers(superpowers) → regen vendors 64;verify-rigs.sh63→64 count + fenced-stripped../([a-z0-9-]+)/sibling-doc-ref gate +"*\t-p*"terminal deny + terminality assert (no allow after deny block) + renderer-emit check;render-seat.pyterminal tuple +="*\t-p*";gate-role.sh+= tab--p+--full-diff+--textconvdeny probes (4/4 flags);tests/test_render_seat.py+= tab deny;generate-rigs.pydocstring 63→64; audit prompt Beta/5.5/Domain-6/6.1 claims → 64 skills + 15 denies + sibling-resolves invariant. No check weakened; 20×builtin:locked,*..*deny-last, triple-deny,!cat, loopback/pinned sidecars preserved. - Shell host MUST:
HERETEK_RIGS_ALLOW_DIRTY=1 python3 scripts/generate-rigs.py(expect 64 shared skills + 15 terminal denies) →./scripts/verify-rigs.sh --check-only→python3 ./scripts/audit_loop.py --self-test→python3 scripts/generate-rigs.py --check-idempotent→ scratch-copy sabotage trios (rmusing-superpowerssibling; delete"*\t-p*"; trailing-allow inject — each must flip gate 0→1) → commit →audit_loop.pyspawns next triad audit. Full per-HR mapping inREMEDIATION_LOG.mdlatest entry.AUDIT_REPORT_FINDINGS.mduntouched.
2026-10-24 — Audit #66 remediate-foundation M0 baseline (wave remediate-foundation)
./scripts/verify-rigs.sh --check-only→SUMMARY: 27 checks passed, 0 failed.(exit 0)make test→Ran 125 tests ... OK(7 suites: test_render_seat, test_sweep_typed_blocks, test_regen_gate, test_queue_id_discipline, test_queue_json_discipline, test_reconcile, test_generate_trackers)- Orphans confirmed present-but-unwired: tests/test_check_envelope.py, tests/test_build_canary.py, tests/test_live_health.py (also tests/test_manifest_closure.py, tests/test_policy_verifier.py — wired via verify-rigs V8/V9, NOT Makefile; untouched this wave per brief)
bwrap --version→bubblewrap 0.13.1;unshare --user --map-root-user true→ exit 0 (no output)- Toolchain: pps at $HOME/.local/share/heretek-rigs/tools/pi-packages/node_modules/@gotgenes/pi-permission-system/package.json version 41.0.0;
pi --version→ 1.3.0;node --version→ v26.10.0
2026-10-24 — Audit #66 remediate-foundation M1 shellPath spike (wave remediate-foundation)
- Scratch: mktemp -d outside repo (/tmp/tmp.CrKXE2UH7M); rendered engine-systems-eng (game-dev-and-sim-rig/engine, mock provider, dummy 0600 secrets); settings.json shellPath → trivial wrapper
echo "MARKER-SHELLPATH-HIT: $2" >&2; exec /bin/bash "$@"; drove with scripts/gate-run.sh - Allowed
date +%soutput:"text":"MARKER-SHELLPATH-HIT: date +%s\n1792813910\n"+"exit_code":0,"isError":false→ MARKER PRESENT (shellPath honored) - Denied
date +%s; idoutput:"text":"[pi-permission-system] Denied by policy: 'bash' (rule '*')"+"isError":true, NO marker → enforcer-first (policy-denied command never reaches wrapper) - NOTE: settings.json is NOT hot-reloaded (pi reads at startup; RPC reload only) — M4 sandbox rollout needs each seat relaunched or sent an RPC reload, NOT a no-bounce change. The permission config.json DOES hot-reload on mtime, but shellPath lives in settings.json.
2026-10-24 — Audit #66 remediate-foundation M2 fail-closed pps check (wave remediate-foundation)
scripts/render-seat.pybuild_seat_files: after pps_pkg built, fail-closed die on missing package.json ({pps_pkg} missing: @gotgenes/pi-permission-system is mandatory) + pinned-version assert (41.0.0); gated on check_secret_fs only, NO --allow-missing-secrets escape- Acceptance 1:
HERETEK_TOOLS=/nonexistent HERETEK_SECRETS=$(mktemp -d) python3 scripts/render-seat.py --role exec-director --rig executive-and-architecture --pod exec --allow-missing-secrets --out $(mktemp -d)→error: /nonexistent/pi-packages/node_modules/@gotgenes/pi-permission-system missing: @gotgenes/pi-permission-system is mandatory, exit=2 (non-zero with mandatory message) - Acceptance 2: version-drift probe (scratch tools dir with package.json version 40.0.0) →
error: ... version 40.0.0, need 41.0.0, exit=2 - Acceptance 3: real HERETEK_TOOLS render exits 0 (
rendered exec-exec-director@executive-and-architecture, only a github-secrets warning)
2026-10-24 — Audit #66 remediate-foundation M3 tool-existence gate + orphan wiring (wave remediate-foundation)
scripts/verify-rigs.shnew== V12 ==block (appended after V11, no V1-V11 renumber/reword): (a) asserts M2 guard strings present in render-seat.py source (fail if deleted); (b) per-seat committed runtime/pi-settings.json packages[0] must be the mandatory pps, and when the tools dir exists its package.json must exist at version 41.0.0 (fail); (c) every stdio MCP server bound to a seat: @TOOLS@-absolute command must be a file, bare command must resolve via shutil.which — missing REPORTED per seat via [NOTE] (naming e.g. radare2/r2mcp) without failing. Severity decision: fail on mandatory pps/guard, list host-optional MCP binaries — keeps the gate green on hosts without full tooling (this host lacks playwright-mcp, chrome-devtools-mcp, mcp-server-mobile, mcp-openapi-schema-explorer, r2mcp, mcp-server-memory, kubernetes-mcp-server) while naming each gap per seat; host tooling completeness is M9 scope.tests/test_render_seat.py: setUp fixture HERETEK_TOOLS /opt/hr-tools (nonexistent) died under the new M2 guard (6 failures) — fixture now uses a scratch tools dir carrying pinned pps package.json 41.0.0 (invariant adaptation, NOT weakening); packages assertion updated to self.tools; +2 new tests (missing pps dies despite --allow-missing-secrets; 40.0.0 drift dies). Suite now 9 tests, all pass.- Cosmetic discrepancy (NOT changed, per never-reword-V1-V11): V6 ok() message still reads
tests/test_render_seat.py (7/7 unit tests) passedwhile the suite now runs 9 tests; the gate keys on returncode 0 so it stays green. Makefiletest: target now lists all 10 suites (+ test_build_canary, test_check_envelope, test_live_health); test_manifest_closure/test_policy_verifier stay verify-rigs-V8/V9-wired only (untouched per brief).- Acceptance:
make test→Ran 208 tests ... OK(10 suites confirmed in output);./scripts/verify-rigs.sh --check-only→SUMMARY: 28 checks passed, 0 failed.(27 + V12)
2026-10-24 — Audit #66 remediate-sandbox M4 sandbox every execution-capable seat (wave remediate-sandbox)
Env-mechanism decision (validated, NOT assumed)
- Requirement: HERETEK_SANDBOX_WRITE + secret-store path must be present in the seat's LAUNCHED environment (wrapper reads env at seat runtime).
- Dead end 1 — daemon env: @openrig/cli
daemon/dist/adapters/pi-runner-protocol.jsbuildPiChildEnv(lines ~150-189) is deny-by-default — only PATH/HOME/USER/LOGNAME/TERM/LANG/LC_ALL/SHELL/TMPDIR + OPENRIG_* + PI_CODING_AGENT_DIR/SESSION_DIR + the declared provider key cross into the pi child. A HERETEK_* var set in the daemon env dies at the child boundary. - Dead end 2 — rig
env::daemon/docs/reference/rig-spec.md"Where the declared names reach, by runtime" states explicitly: "On Pi and OMP seats the values reach the terminal. The agent process gets only what the runner passes on, so a spec or one-off value reaches it only for the names the runner always passes: PATH, HOME, USER, LOGNAME, TERM, LANG, LC_ALL, SHELL and TMPDIR." Memberenv:therefore cannot carry per-seat sandbox roots to pi either. - Chosen mechanism: render-seat.py writes
sandbox.env(HERETEK_SANDBOX_WRITE=<colon-joined bind roots>,<store var>=<secrets_dir>, shlex-quoted) into the seat agent dir; seat-sandbox.sh bootstraps it from$PI_CODING_AGENT_DIR/sandbox.envwhen the vars are unset. PI_CODING_AGENT_DIR is unconditionally set in the pi child env (buildPiChildEnv line ~157; pidist/config.jsgetAgentDir()reads it) and inherited by the bash-tool shell — per-seat correct under multi-seat daemon launch, no shared-env collision, no new host dependency. - Deviation from the spec block (recorded): the M4 block was copied functionally verbatim, PLUS a marked M4 bootstrap preamble (source sandbox.env via PI_CODING_AGENT_DIR). Without it the wrapper would see empty roots on every real seat (env cannot cross the runner boundary — verified above). The bwrap core below
set -euo pipefailis byte-identical to the verified block. Fail-closed preserved: no roots (no env, no file) = whole tree read-only except scratch. - Bind-root normalization (renderer
_sandbox_bind_roots): path_write globs are pps match patterns, not literal dirs, sotests/chaos/*->tests/chaos; file globs (*package-lock.json) and bare file names (package.json) map to their parent dir (.= seat cwd). Coarse by design: pps stays the fine-grained gate (F1 enforcer-first); the jail adds cwd-containment + no-net + masked store. Known limitation: seats whose path_write is file-only (e.g. dependency-patcher, static-analysis-lead) get cwd bound writable — policy still enforced by pps.
Locked-seat runner-verb audit (all 18 locked roles dumped via python3+yaml; removals)
- ai-red-teamer: removed
garak*,pyrit*,promptfoo*(red-team runners execute payloads). - compliance-auditor: removed
npx license-checker*,cargo license*(npx executes code; cargo runs build scripts.syft dir*stays: static SBOM scanner). - sabotage-qa-tester: removed
npx stryker run*,cargo mutants*,mutmut run*,npm test*,pytest*,cargo test*. - static-analysis-lead: removed
npx biome check*,cargo clippy*(clippy runs build scripts per #68(a); npx executes code.semgrep --config*,ruff check*stay: static scanners). - Other 14 locked seats: audited, no test-runner/interpreter verbs — kept read-only scanners/static tools (semgrep/trivy/r2/rabin2/strings/tshark/checkov/tfsec/gitleaks/syft/readelf/objdump/checksec/binwalk/markdownlint, git branch/merge-base/status/diff/log/show, rig whoami/ps/queue/send/capture/transcript).
- Standard seats untouched: dependency-patcher keeps npm test*/cargo test*/pytest*/go test* (builtin:standard); rust-systems-spec keeps cargo clippy*/cargo test*; go-backend-eng keeps go test*; python-backend-spec keeps pytest*; ts-node-fullstack keeps npm test*.
- dependency-patcher (#73): removed
git checkout*,git commit*(it was the only commit grant in the fleet;git checkout -- <path>was already denied by path-arg policing). - fleet.yaml: added top-level
sandbox:write-roots schema block (write_roots_source: permissions.path_write, wrapper, env_file). Surgical text edits only, no yaml.safe_dump (verified:python3 -c yaml.safe_loadparses; regenerated leaves byte-correct).
HR-4.4 trip (self-caught, fixed)
- First regen green except 1 fail:
fleet/fleet.yaml contains forbidden reserved/secret env name— the sandbox comment spelled the store variable name (matches_SECRET). Fixed by rewording the fleet comment to never name credential env vars (name lives only in scripts/render-seat.py + scripts/seat-sandbox.sh, which that scan does not cover); own meta-comment tripped once more, reworded again.grep -c "_SECRET|_TOKEN|_PASSWORD" fleet/fleet.yaml→ 0; verify back to 28/0.
F2 corpus under the jail (bwrap 0.13.1, PI_CODING_AGENT_DIR=, HERETEK_* explicitly unset to prove file bootstrap)
echo ok > tests/chaos/t.txt→ rc=0 (in-scope bind) ✓echo x > root.txt→ rc=1Read-only file system✓cat ~/.config/heretek-rigs/secrets/opencode-go.key→No such file or directoryrc=1 (tmpfs mask) ✓curl -sS -m 8 https://example.com→ rc=7 Could not connect (net blocked) ✓git status --short→ works, rc=0 ✓seat-sandbox.sh(no args / 3 args) →expected -c <command>rc=126 ✓
Acceptance
bash scripts/gate-role.sh sabotage-qa-tester→ exit 0, all probes ok; rendered pi-permission-config.json bash allows = 11, zero runner-ish (test|stryker|mutant|mutmut|pytest|cargo|garak|pyrit|promptfoo|npx|clippy).HERETEK_RIGS_ALLOW_DIRTY=1 python3 ./scripts/generate-rigs.pytwice → byte-identical diff (cmp clean = idempotent); 223 files changed (51×2 pi-settings shellPath + permission strips + registry/rigs leaves)../scripts/verify-rigs.sh --check-only→SUMMARY: 28 checks passed, 0 failed.(V12 extended: shellPath/sandbox.env renderer asserts, wrapper exists+executable, bwrap resolves, per-seat shellPath suffix).make test→ 210 tests, 1 failure: tests/test_build_canary.py::test_canary_scope_only (pins fleet permissions to basea33f3bballowing ONLY engine-systems-eng to differ; M4 legitimately changes 5 roles). Genuinely stale vs mandated M4 change → adapting the bound in its own commit (next), one-line reason recorded here: M4 #68/#73 strips change exactly ai-red-teamer, compliance-auditor, dependency-patcher, sabotage-qa-tester, static-analysis-lead.- Worktree vendor symlink:
.scratch/vendorsymlinked to the main checkout's.scratch/vendor(7 pinned clones, 74M) — worktrees do not carry ignored scratch; generate reads vendor only. Recorded so a fresh worktree setup repeats it.
Rollout split (stated in stage report + draft PR text there)
- NOT no-bounce (needs relaunch or RPC reload per seat): settings.json
shellPath(F1: pi reads settings at startup only) — the sandbox itself. - Canary-then-fleet WITHOUT bounce (permission config.json hot-reloads on mtime): git-diff terminal denies (M5), locked-seat verb removal, dependency-patcher commit strip, MCP flags.
2026-10-24 — Audit #66 remediate-sandbox M5 git-diff bypass + identity forgery (wave remediate-sandbox)
Deny additions (renderer + mirror + asserts, kept identical)
- render-seat.py terminal tuple appended (same order as verify mirror):
* -u*,*\t-u*,* -U*,*\t-U*,*--unified*,*--cc*,* -c *,* -m *,* -W*,*--function-context*,*--word-diff*,*--color-words*,*--binary*,*--raw*, plus*OPENRIG_SESSION_NAME=*,*OPENRIG_URL=*. - Over-block pre-scan (python3+yaml+fnmatch over all 51 roles): NO fleet bash_allow contains any new deny infix as a literal substring — emission is purely additive. Anti-overblock probe (
git log --oneline -- README.md) still allows post-regen (gate-role green). - verify-rigs.sh: :588 mirror tuple extended identically (order matches emission; sortedness + no-allow-after-deny gates hold); :1153-1160 renderer asserts extended to all 16 new denies. tests/test_render_seat.py deny tuple extended likewise.
send-authenticated.sh hardening (#72, #93)
- Top-of-script: exit 2 when OPENRIG_SESSION_NAME is set (refuse, never silently unset). Verified:
OPENRIG_SESSION_NAME=exec-...@... ... --destination ...→error: refusing ..., rc=2. - Receipt fail-closed: state must be in {pending, in-progress} (rc=5), persisted===true (rc=6), no createWarning (rc=7); pre-existing qitemId/state presence (rc=4) kept. Stub-rig matrix (PATH-shadowed
rigexecutable):{"state":"failed","persisted":false}→ rc=4; +qitemId failed/false → rc=5; pending/true+createWarning → rc=7; pending/false → rc=6; pending/true and in-progress/true → rc=0created .... - BUG FOUND BY THE STUB TEST (fixed, not shipped): first version used
d.get('createWarning')inside an f-string withinpython3 -c '...'— bash strips nested single quotes before python sees them, so python receivedd.get(createWarning)→ NameError → rc=1 via the generic path. Fixed by hoisting to_w/_ptemp vars (no inner quotes). Lesson recorded: never nest single quotes insidepython3 -c '...'in shell scripts. - --source: existing @-rejection kept; ADDED fleet member/role-id rejection (python3+yaml over fleet/fleet.yaml relative to the script dir: all role ids, rig pod member ids, omni core/pod/member ids; fail-closed rc=2 if catalog unreadable, uv fallback for PyYAML). Verified:
--source exec-director→ rc=2not a fleet member/role id;--source blue-appsec@rig→ rc=2 (@-form);--source operator --dry-run→ rc=0.
gate-role.sh probes + F9 residual evidence
- Added after :76 (canary :32-40 and anti-overblock probes untouched):
git log --oneline -u,git log --oneline --cc,env OPENRIG_SESSION_NAME=x rig whoami— all expect-deny. bash scripts/gate-role.sh go-backend-eng→ exit 0, 43 ok / 0 FAIL (includes all M5 probes + pre-existing anti-overblock allow).- F9 residual CONFIRMED live (scratch render + gate-run.sh, mock model): bare leading
OPENRIG_SESSION_NAME=x rig whoamiEXECUTES (rc=0, rig resolved sessionx) — pps strips the leading assignment before matching so the*OPENRIG_SESSION_NAME=*terminal deny never sees it;env OPENRIG_SESSION_NAME=x rig whoamiDENIES (isError:true). Consequence: the task text's literal probe (OPENRIG_SESSION_NAME=x rig whoamiexpect-deny) would fail against real pps behavior, so the committed probe uses the env-prefixed form and the leading-assignment form stays closed at the send-authenticated.sh layer (+ upstream request, per F9). Discrepancy vs task text is intentional and evidence-backed. - generate-rigs.py:493 charter denial-classification text still lists only the pre-M5 terminal guards — NOT updated (charter prose, out of M5 scope; suggested M10/PR follow-up so seats decode the new denial patterns).
Acceptance
bash scripts/gate-role.sh go-backend-engdenies all new git-diff forms and the env-prefixed rig call (43/0, exit 0).- send-authenticated.sh with OPENRIG_SESSION_NAME set refuses (rc=2); fake
{"state":"failed","persisted":false}exits non-zero (rc=4; fuller fakes rc=5/6/7). ./scripts/verify-rigs.sh --check-only→SUMMARY: 28 checks passed, 0 failed.;make test→Ran 210 tests ... OK; generate-rigs ×2 byte-identical (cmp clean).- Rollout split (unchanged from M4): sandbox shellPath needs relaunch/RPC reload; permission config.json changes (these M5 denies, M4 verb removals) go canary-then-fleet without bounce.
2026-10-24 — Audit #66 remediate-governance M6 evaluator hardening (#79, wave remediate-governance)
Derivation (issue bodies not on disk)
- Full #79/#83/#84/#92 issue texts are NOT in the repo (searched docs/ + repo-wide grep: only the reaudit table rows in docs/PROMPT_REMEDIATION_REAUDIT.md name them). The 8 M6 vectors and the M8 #92 row list are therefore DERIVED from the M6/M8 spec sentences + the reaudit one-liners, per the wave brief ("derive rows ... and record derivation"). Derivation recorded per milestone below.
M6 decision record (scripts/audit_loop.py)
- Header:
^#{1,6}\s*HR-[\w.-]+(any ATX depth, colon optional). Kept MULTILINE over combined report+agent text; gate-fail and explicit-FINDINGS_DETECTED short-circuits unchanged. - Ledger: every pipe-delimited line scanned per-cell; each cell stripped of
[*_~\]+and emoji (U+1F300–1FAFF, U+2600–2BFF incl ❌ U+274C, variation selectors, ZWJ, regional indicators), then\b(BROKEN|PARTIAL)\b` IGNORECASE. Table-wide (not ledger-section-only) so fenced/bare/decorated rows all trip; prose-only "broken" still does NOT trip (pipe-scope kept deliberately to avoid matching narrative words like "broken" in a clean verdict). - Defect-Matrix P-grade: body cells only (header + separator rows skipped), in tables under a "defect matrix" heading OR whose header row has an exact-ci "Priority" cell. Case-insensitive
P[0-3](adversarial lowercasep1launders nothing). Known over-approximation: a P-grade token in any Priority-columned table counts even outside the matrix section — fail-closed by design. - Sabotage: body rows only, in tables under a "sabotage" heading OR with an exact-ci "Caught?" header cell; last cell stripped of decorations, lowercased, must equal
yes. Verifies against the template shape (| Invariant | ... | Suite result | Caught? |, PROMPT_ADVERSARIAL_FLEET_AUDIT.md:285). - Real-file sanity: current AUDIT_REPORT_FINDINGS.md short-circuits on its explicit FINDINGS_DETECTED sentinel (unchanged); table scan alone gives (ledger=24 PARTIAL rows, matrix=0 — the
_none_row correctly trips nothing, sabotage=12 UNVERIFIABLE rows) — consistent with pre-fix behavior (pre-fix regex also tripped on PARTIAL). - RED proof: all 8 derived vectors return NO_FINDINGS on pre-fix code (scratch /tmp/opencode/red_m6.py, 8/8 MISS), FINDINGS_DETECTED post-fix (self-test asserts). The 7 pre-existing vectors kept verbatim (none subsumed: bare/lowercase/fenced are syntactically distinct from decorated/matrix/sabotage shapes).
M6 acceptance
python3 scripts/audit_loop.py --self-test→ exit 0,Fail-closed sentinel evaluator verified against 15 adversarial test vectors(7 kept + 8 new, each asserting FINDINGS_DETECTED).
M7 decision record (governance gates, #83 #84)
- TPM-seat set source: read-only
yaml.safe_loadoffleet/fleet.yaml(script-relativePath(__file__).parent.parent / "fleet" / "fleet.yaml", so CWD-independent). Set = everyroles:key containing tpm/scrum + session/address ids (and @-local-parts) of members whoserole:contains tpm/scrum, found by generic tree-walk (covers omni pod fragments,session:/address:spellings,reports_toblocks). Fleet-grounded check: set containstpm-scrum-leadanddelivery-tpm-scrum-lead@executive-and-architecture(asserted in-test). Today that is exactly one seat;operatorstays authoritative by prefix rule alongside it. Unreadable catalog -> empty set (only operator authoritative: stay-blocked bias). Each script carries its own loader copy (no shared import; matches the sweep module's no-shared-files convention). - sweep-typed-blocks.py, auth:-only changes: (a) SATISFIED: requires the parsed blocker to EQUAL
blockedOnexactly (removed theblocker_key_tokensoverlap OR-branch and thenote_names_blockersubstring matcher from the auth: path); (b) SATISFIED: author must be operator/TPM (self-written notes suppressed with a named reason); (c) SATISFIED: evidence must cite >=1qitem-*ref, still resolution-checked via the fetcher (dangling -> stay-blocked + retry); (d) legacy-note path requires the FULLauth:<what>string in the note (case-insensitive containment — the exact-string analog inside prose) plus sat-tokens with no rearm plus cited-or-authoritative (authority = operator OR TPM for auth:). Rearm detection stays token-based for auth: (fail-closed direction: it can only keep rows blocked). Non-auth: (external:/fold:) paths byte-identical in behavior (operator-only authority, overlap matching kept) — pinned by a scope-guard test (external: overlap still unparks). - #83 case A = self-written SATISFIED: (owner@fleet author) -> stay-blocked; case B = token-overlap blocker (
auth:wave2-tpmvs parkedauth:wave2-tpm-release, overlap asserted non-empty in-test so the fixture is non-vacuous) -> stay-blocked, plus the legacy-overlap-note variant. Fleet-default path tested without explicit pass-through (TPM actor + default set -> unpark); empty-set catalog failure -> TPM not authoritative, operator still is. - reconcile_model.py:
queue_terminalis now entry-state OR latest-transition-state in TERMINAL_QUEUE_STATES — theTERMINAL_NOTE_REclause AND the constant are removed (repo-wide grep: no other importer; generate_trackers/reconcile docstrings + QUEUE_TO_TRACKER_MAP reworded to state-only). Tracker/note affirmation helper_affirmative_qa_pass:^QA PASS\b(case-insensitive, leading-space tolerant) AND no negator (\b(not|no|never)\born'tincl. curly apostrophe — word-boundary-safe so "note"/"canonical" don't false-positive) AND no fail token (fail/failed/fails/failure/failing).placed/closedkeep substring detection but are void under negation/fail;staged/dispatched/parkedunchanged. Caveat recorded: a legit cell like "QA PASS, no issues" is now non-terminal (spec-literal negator list); the canonical emitted cells never contain standalone no/not/never/n't/fail tokens (verified: converged + replay suites green). - RED proof: 6/7 new reconcile tests failed pre-fix (note-terminality), 9/11 new sweep tests errored pre-fix (missing API) with the overlap/self-written cases asserting the old unpark. Post-fix: full
make test228 tests OK (210 + 11 sweep + 7 reconcile), audit self-test green. - #84 fixture ("QA pass NOT granted; NOT placed", state in-progress): with a terminal-claiming tracker cell, reconcile exits 1
stale-state("tracker claims terminal while queue is in-progress", noPROPOSED-CELL:::QA PASS); generate_trackers exits 1 NEEDS-HUMAN-REVIEW with zeroPROPOSED-CELL:::markers. (Pre-fix both exited 0 "in sync": the negated note matchedqa\s*pass-> terminal=True and the recorded note id converged the row.) A negated tracker cell itself resolves to OTHER + NEEDS-HUMAN-REVIEW via generate_trackers.
M7 acceptance
- #83 cases A and B return stay-blocked (new TestAuthBlockerHardening, 11 tests).
- #84 fixture exits 1 NEEDS-HUMAN-REVIEW with no paste-ready PASS cell (new TestNegationAwareTerminal, 7 tests).
- Existing tests/test_sweep_typed_blocks.py (43) + tests/test_reconcile.py (29+7=36 incl. new) + rest of suite:
make test228 OK.
M8 decision record (envelope semantics, #92, wave remediate-governance)
- #92 row derivation: the issue body is not on disk (searched docs/ + repo-wide; only the reaudit one-liner names
.git/hooks, AGENTS.md, fleet/, PUSH main, 9999 expiry, issued-after-expiry, BY WHOM nobody). The enforced row set is derived from the M8 spec sentence + that one-liner; 20 new tests (TestEnvelopeSemanticsM8) pin one row each. Rows enforced: 11 path scopes (.git/hooks/x,.pi/agent/x,.agents/y,fleet/fleet.yaml,scripts/run.sh,AGENTS.md,docs/AGENTS.md,-evil,src/a:b, non-ASCIIsrc/café/,src/100%x/), PUSH main, PUSH master, 9999 expiry, issued-after-expiry, future-issued, multi-deadline min-governs, unknown owning seat, BY WHOM nobody, BY WHOM non-TPM seat, unlinked audit record. - Path scope: new denies appended after (not before) the existing absolute/
../root-alias/home/glob checks, so pre-existing messages are byte-identical. Leading.catches.git/.pi/.agentsheads; an interior-segment check catchessub/.git/x;fleet/scriptsare prefix-or-equal; AGENTS.md is basename-equal (any dir).:is refused incheck_path_scopefor head-line values; body-line colons never reach it (the section parser divertsWord:lines into unknown sections — refused either way; the colon test pins the outcome, RED pre-fix confirmed except this one row which already refused via the parser, now double-layered). - PUSH:
branch.upper() in (HEAD, MAIN, MASTER)refused up front with atrunkmessage; the old trailing HEAD clause removed as subsumed.PUSH feat/wave-12-canarystill ACCEPTs (control). - Spec-mandated test inversion (rule 4, one-line reason):
test_push_bare_main_acceptedcontradicted the #92 row set (the spec sentence says every #92 row returns REFUSE and the reaudit names PUSH main explicitly), so it is nowtest_push_bare_main_refusedasserting rc=1 +trunkin output. No other test touched. - Expiry:
findalloverexpires <stamp>+min()governs; chain enforced isissued_at <= now < deadline <= issued_at + 14d(14d = ENVELOPE_MAX_LIFETIME_DAYS). Single-slice (no deadline) requiresissued_at <= now. The old "'expires' without parseable deadline" branch is subsumed by "neither single-slice nor deadline" (same refuse). Multi-deadline with a far-future second deadline but live min is ACCEPTED (min governs per spec — recorded as accepted interpretation). - Seats:
fleet_gate_sets()(own copy in check-envelope.py) reads script-relativefleet/fleet.yamlvia yaml.safe_load: vocab = lowercased role ids +role:values +session:/address:values + @-local-parts (153 entries; includes engine-systems-eng, cpp-lowlevel-eng, go-backend-eng); tpm_ids = the 3 tpm/scrum-bound ids (tpm-scrum-lead,delivery-tpm-scrum-lead@executive-and-architecture,delivery-tpm-scrum-lead). Unreadable catalog -> Refusal (fail-closed, operator holds). Owning-seat order: token-shape first, then catalog membership. - BY WHOM: void set (nobody/none/n-a/na/tbd/todo/unknown/unnamed/anonymous/anyone/someone/vacant, trailing-dot tolerant) -> refuse; owning-seat substring (legacy) -> refuse (checked BEFORE TPM acceptance so a TPM seat can never verify its own work); bare
TPM/TPM-seat-id -> accept (the template designates the role "TPM" and the fleet staffs exactly one tpm/scrum seat — if a second TPM seat ever appears this shorthand turns ambiguous and must be retired); other fleet seat ids -> refuse; anything else -> named human, accepted and audit-recorded. Limitation recorded: single-token garbage ("xyz123") accepts as a "named human" — no human registry exists to check against; the value still names a party in the audit trail. - Audit: per-record link-shape over numbered records (continuation lines appended). Link-shaped = http(s):// | qitem:// |
qitem-<digits>-<alnum>| hex run >=7 chars containing a digit | the word "commit" (the template's canonical execution line "The execution record commit SHA + ..." cites no SHA, so bare "commit" must count — definition calibrated to keep both ACCEPT fixtures green) | slashed path token. Keyword mapping kept (envelope/verif/execution-or-commit), each mapped record must carry a token. Existing two-link test still refuses on the missing keyword. - RED proof: 19/20 new tests failed pre-fix (rc=0 ACCEPT); the 20th (colon path) already refused via the section parser and now pins double-layer refusal. Post-fix: full
make test248 OK (228 + 20 new), verify-rigs 28/0 untouched.
M8 acceptance
- Every derived #92 row returns REFUSE (rc=1): 20 new tests + inverted PUSH-main test, all green.
- Existing suite preserved: 69/69 tests/test_check_envelope.py OK (48 unchanged + 1 spec-mandated inversion + 20 new);
make test248 OK;verify-rigs.sh --check-only28/0.
2026-10-24 — Audit #66 remediate-supplychain M9 supply-chain + registry gates (wave remediate-supplychain)
Baseline (pre-change, worktree remediate/audit-66-p0-p1-supplychain @ 27876bd)
./scripts/verify-rigs.sh --check-only→SUMMARY: 28 checks passed, 0 failed.(exit 0)make test→ 248 tests OK expected (10 suites; will confirm with run).scratch/vendorsymlinked →/home/john/Projects/heretek-rigs/.lane/trees/remediate-supplychain/.scratch/vendorabsent in worktree; created symlink to main checkout's.scratch/vendor(7 pinned clones, git-ignored, same as Wave-2 setup). All clones clean, SHAs match pins (obra bb92a77, tob 5c99c03, sentry f57ada2, anthropic dbd4588, vercel 063bee9, supabase c9be0e9, prisma ba3f9d7); Heretek-Crew @ 0b41346 (allowed alt); openrig-core resolves vianpm root -g@openrig/cli.git archive <sha> <path>verified working on a vendor clone (obra_superpowers bb92a77 skills/systematic-debugging lists SKILL.md + companions withskills/prefix → extractor must relocate<tmp>/<relpath>to dst, not blind-strip).
Image digest resolutions (all resolved on-host 2026-10-24, NEVER from memory)
- Network ONLINE (docker.io + ghcr.io anonymous token OK — verified via ghcr.io/astral-sh/uv control).
tecnativa/docker-socket-proxy:0.5.0→ MANIFEST UNKNOWN (tag does not exist; onlyv0.5.0). Real:v0.5.0→sha256:1f5038b54f06c3e18422902cf00ba21803d1c97805aae032e5e6673d532d3459(skopeo inspect docker://tecnativa/docker-socket-proxy:v0.5.0).searxng/searxng:2026.10.18-2c9b2d4→ MANIFEST UNKNOWN. Upstream Heretek-Crew pins taglesssearxng/searxng@sha256:79180616c984f39524f6f27f19625a46f82c8ad4aa6a2e553db52b14e1b4a768— verified live viaskopeo inspect docker://searxng/searxng@sha256:7918…(digest echoed back). Adopted (cross-repo consistency with sibling-tested pin).browserless/chrome:1.66.0→ MANIFEST UNKNOWN (no bare semver tags at all; scheme is<ver>-<variant>-<vv>). Upstream pinsghcr.io/browserless/chromium:v2.26.0@sha256:899026f6995003a35989dc32e240711735ac17069a9f5b310ecf236d082899c5e…— verified live (digest echoed). Adopted (repo fix docker.io browserless/chrome → ghcr.io browserless/chromium).ghcr.io/mendable/firecrawl:1.6.0→ DENIED (orgmendablehas no such repo; org renamed mendableai→firecrawl per GitHub API redirect repositories/787076358). Upstream pinsghcr.io/firecrawl/firecrawl:2.10.19@sha256:50446cbc0bc700a78cc588c96bd38a97f01cc4299c99b349c7bfa1ba57b6d7ed— verified live. Adopted. Upstream runs PORT/INTERNAL_PORT 3002 (image default is 8080 per config inspect of 2.11.605) → our compose gainsPORT: "3002"+INTERNAL_PORT: "3002"env to preserve the 3002 mapping. Caveat: upstream runs a full backing stack (rabbitmq/nuq-postgres/playwright-service); our minimal profile keeps firecrawl-redis only — standalone boot unverified, recorded as follow-up.ghcr.io/ghidra/ghidra:11.4.2→ DENIED (noghidraGitHub org exists — 404; phantom reference). Upstream pinsblacktop/ghidra:12.1.4@sha256:b2479177bd6a10d974da1bff30cc911ea2856843d858ad0ba02a608152ca193c— verified live. Adopted with upstream's entrypoint["/entrypoint.sh"]+ command["server"](blacktop default cmd isclient;serverserves :1337 per upstream healthcheck probe).radareorg/radare2:5.9.8→ DENIED on docker.io + object-not-found (repo does not exist on Hub). Real:radare/radare2:5.9.8(417 tags incl. 5.9.8) →sha256:4fcb018e7f2351f370eafd4e7006b6ba476a475f587978b34cf494617ad7ef10. Upstream pins taglessradare/radare2@sha256:88b7ff67710e12f430b269abc7714490e3a0c37e391521523148cbd6f9d2ae37— verified live. Adopted (org fix + digest).sonarqube:25.10.0-community→ MANIFEST UNKNOWN. Real tag25.10.0.114319-community→sha256:ef0290a2deabad86a2623552712033a7107a9f5b310af00519b4ddd5b348ef4e(spec's resolved tag confirmed on-host).redis:8.0.3→sha256:be0a135f1955140436b9114da96dd22fbedb874469400b6ef458cc0d42155de0✓ (kept tag, digest added).qdrant/qdrant:v1.15.3→sha256:31407c0e8e32eb771b71718f1a4772e2ad47a07557917b21ac96792f40eb8007✓ (kept tag — upstream at v1.19.2, delta recorded, no bump: minimal-diff principle).budtmo/docker-android:emulator_14.0→sha256:8ee678cf831fdf7c03fb391ca036922f3b78b89fdc992be3b815e1c70b372d2a✓ (kept tag — upstream more specific emulator_14.0_v3.8.0-p1, delta recorded).- Pre-existing phantom-tag evidence: NONE of the 4 wrong tags (
:0.5.0,:2026.10.18-2c9b2d4,:1.66.0,:25.10.0-community) resolve;docker compose pullon the current file fails today. M9 fixes this.
Implementation (M9 code changes)
scripts/generate-rigs.py:vendor_skill_from_clone()(git archive <sha> <path>→ tmp → relocate, dies on missing/dirty clone, unresolvable SHA, archive failure, missing SKILL.md); pins-loop + helper refuse TRACKED modifications (--untracked-files=no; untracked strays tolerated — the #43 class — becausegit archivereads commit objects only, so strays cannot influence bytes; the Heretek-Crew checkout itself carries?? docker-compose.override.yml+?? heretek-rigs/strays, which must not block vendoring); shared-pool (non-openrig-core) + role_local call sites converted; openrig-core keeps copytree (ships in the npm package, not a git clone — recorded).resolve_run_attestation()readsdocs/evidence/run-records.json→ ("tested", ids) or ("Not tested", []); listings platforms + harness result wired.resolve_heretek_commit()stampsDIRTY-<sha>when BLOCKING dirt exists under ALLOW_DIRTY (sanctioned-only strays still record bare SHA).scripts/render-seat.py: terminal denies hoisted to moduleTERMINAL_BASH_DENIES(31 entries, ordered-identical to the:588mirror — verified by eval-compare); emitter loop now iterates the constant. tests/test_render_seat.py tuple left as-is (test-side expectation).scripts/verify-rigs.sh: V6:1300proxy assert updated to the verifiedv0.5.0@sha256:1f50…3459(spec-mandated stale-pin update — the old assert pinned a nonexistent tag; same precedent as M8's PUSH inversion). New== V13 ==block (S2a + #70/#71/#85/#86/#87/#97/#99, one ok()): S2a tuple-sync via module import; per-service tag@digest format + skopeo existence (digest-ref probe; transport-error offline skip, manifest-unknown fail); Dockerfile-vs-catalog/fleet exact install-list match (11 pins both directions); MCP exact flags + pin==args-pin (uvx/docker commands; npm-command servers covered by the Dockerfile assert); r2mcp/aws-mcp banned forms (active-line vsreplaces:distinction in catalog; zero-tolerance in fleet/specs/rigs/scripts); git-archive + dirty-refusal source asserts; roster==51 sessions + command pod == {exec-director, system-architect, tpm-scrum-lead} lead exec-director; stub scan (skills/ excluded, @TOOLS@/@SECRETS@/@SEAT@ stripped); DIRTY reject; attestation grounded-or-"Not tested" (listings + harness).docker-compose.sidecars.yml: all 10 images tag@digest-pinned (4 repo fixes, 3 tag fixes, firecrawl PORT/INTERNAL_PORT 3002 to preserve mapping, ghidra entrypoint/commandserverto preserve :1337).docker/Dockerfile: OPENRIG_VERSION 0.6.11→0.6.13; context7 4.4.2→4.4.4, server-memory 1.0.0→2.0.0 (catalog alignment).Makefile: 11th suite (test_generate_supplychain) wired intotest:(per #82, no orphans).tests/test_generate_supplychain.py(new, 8 tests): archive-bytes-equal, dirty/unknown-sha/missing-path die, attestation present/absent/malformed/empty.- V13 extraction bugs found by the r1 run and fixed: skopeo rejects tag@digest (probe digest-ref now); bare
proxyin the offline pattern misclassified the proxy image name (nowproxyconnectonly); pin==args-pin scoped off npm-command servers (version bound at install, enforced by the #100 assert); harness path is harnessChecks.harnesses.pi (was missing a level); DIRTY stamps only on BLOCKING dirt (sanctioned-only strays record bare SHA — caught by test_sanctioned_strays_only_resolves, fixed before commit).
Red proofs (each: plant → verify exit 1 with the named gate → restore; full logs /tmp/opencode/sab_*.log)
- 1a tag-only (qdrant digest stripped) →
V13/#70: sidecar qdrant must pin its image by digest✓ - 1b bad digest (redis last-hex flipped) →
V13/#70: sidecar firecrawl-redis image does not resolve(manifest unknown; probe uses digest-ref) ✓ - 2 weakened MCP flag (clickhouse false→true) →
V13/#71: ... must be "false"✓ - 3 r2mcp re-added (
pypi:r2mcp==0.2.5in catalog active lines) →V13/#71: ... active pin contains rejected form✓ - 4 roster member removed (51→50) →
V13/#86: roster seats (50) must equal the 51 fleet sessions✓ - 5 stub marker (
TODOappended to appsec-engineer role.md) →V13/#87: ... contains stub marker 'TODO'✓ (restored via git checkout) - 6 DIRTY stamp (all regen runs above) → 16× V13/#99 + 16× V4 regex rejections ✓
- 7 fabricated attestation (label tested + fake rr id) →
V13/#97: ... tested claim is ungrounded✓ - S2a mirror-only weakening (
*--unified*removed from :588) →V13/S2a: ... must be ordered-identical✓ (Wave-2 QA gap closed) - 85 dirty vendor clone (tracked file tampered in prisma_skills + ALLOW_DIRTY) → exit 2
prisma checkout ... is dirty✓ (restored via git checkout) - Archive fidelity: regen vendored 68 shared skills via
git archive;specs/agents/_sharedbyte-identical (zero diff),fleet/skills-lock.jsonunmodified (tree_hash attests archive bytes). - Incidental: 68 (not 64) shared skills pre-exists in this tree (Waves 2-3 additions); AGENTS.md:46/generator docstring "64" is stale prose — not M9 scope, M10 follow-up candidate.
- pi-settings diffs in this regen are worktree-path artifacts (
.../remediate-sandbox/...→.../remediate-supplychain/...shellPath), not content changes.
Test-fix commit (rule 4, own commit after M9 af3e52e)
tests/test_regen_gate.py::test_allow_dirty_bypass_records_real_shawas genuinely stale under the #99 mandate (ALLOW_DIRTY+blocking dirt now stampsDIRTY-<sha>instead of the bare SHA): updated to expectDIRTY-<head>plus a newtest_allow_dirty_clean_tree_records_bare_sha(sanctioned-only strays + flag → bare SHA). One-line reason recorded here per brief rule 4.
2026-10-24 — Audit #66 remediate-supplychain M10 final pass + verification (wave remediate-supplychain)
Clean-regen + full gates (worktree remediate/audit-66-p0-p1-supplychain @ 2bc45e5, tree clean)
python3 ./scripts/generate-rigs.py(no flag, clean tree) → clean provenance (2bc45e5…, no DIRTY), 16 registry files changed (DIRTY→clean + tested→Not-tested already landed in M9 regen). specs/rigs/status.json byte-identical to M9 commit (same worktree shellPath)../scripts/verify-rigs.sh --check-only→SUMMARY: 29 checks passed, 0 failed.(exit 0; 28 + V13). Log /tmp/opencode/verify_m10_clean.log.make test→Ran 257 tests ... OK(11 suites; 248 + 8 new supply-chain + 1 new regen-gate). Log /tmp/opencode/maketest_m10.log.python3 scripts/audit_loop.py --self-test→ SELF-TEST PASSED (15 vectors: 7 kept + 8 M6).HERETEK_RIGS_ALLOW_DIRTY=1 python3 ./scripts/generate-rigs.py --check-idempotent→idempotence check passed (two consecutive runs byte-identical)exit 0 (both runs stamp the same DIRTY-<HEAD>; determinism proven). Clean leaves snapshotted to /tmp/opencode/leaves_clean/ before the proof and restored after (registry DIRTY-count back to 0).bash scripts/gate-role.sh sabotage-qa-tester→ exit 0 (43 ok incl. all M5 probes);bash scripts/gate-role.sh go-backend-eng→ exit 0 (tail: lsp mutation denies ok).
Per-finding tick table (#67–#102; commands from docs/PROMPT_REMEDIATION_REAUDIT.md §1 unless noted)
- Derivation precedent (Wave 3): issue bodies for #80/#81/#88/#89/#90/#98/#101 are not on disk (searched PROMPT_ADVERSARIAL_FLEET_AUDIT.md, REMEDIATION_IMPLEMENTATION_PROMPT.md, AUDIT_REPORT_FINDINGS.md, docs/reports — zero hits); no wave changed code for them. They tick as follow-up with derivation recorded here.
- #67:
HERETEK_TOOLS=/nonexistent ... render-seat.py --role exec-director ... --allow-missing-secrets→ exit 2 "mandatory" ✓ PASS. - #68: gate-role sabotage-qa-tester exit 0, 43 ok (no runner verb allowed); F2 jail corpus per M4 report (writes confined, net blocked, store masked) — re-ran gate, corpus cited ✓ PASS.
- #69: gate-role go-backend-eng exit 0 (all git-diff forms + env-prefixed rig denied) ✓ PASS (M5 report + re-run).
- #70:
docker manifest inspect tecnativa/...:v0.5.0@sha256:1f50…→ schemaVersion 2, exit 0 ✓ PASS; all 10 digests resolved on-host (see M9 resolutions); V13 existence green. - #71: sabotages 2 (clickhouse true) + 3 (r2mcp re-added) → exit 1 with named gates ✓ PASS.
- #72:
OPENRIG_SESSION_NAME=... send-authenticated.sh→ exit 2 refusal ✓ PASS (env half); live-queue half needs the daemon — residual per F9, upstream request still the path (no wave scope change). - #73: fleet query → 0 roles hold
git commit, dependency-patcher grants empty ✓ PASS. - #74: V12 [NOTE] lines name r2mcp/playwright/chrome-devtools/mobile/openapi/memory/kubernetes per seat ✓ PASS (host-missing listed, gate green).
- #75/#91: NOT IMPLEMENTED —
commandEffectsoccurs only in the two prompt docs (zero code hits). No wave scope. → follow-up (re-audit row documents the desired behavior). - #76: observed DENIED —
ctest --output-on-failurecontains--output, matched by the pre-existing*--output*terminal deny (deny-last). No wave scope; F3 tuple predates M5. → follow-up (needs a policy decision, not a silent edit). - #77: no wave scope (mission-row ownership); needs live queue → UNVERIFIABLE off-fleet → follow-up.
- #78: no wave scope (missions/* + evidence//* writes); M4 sandbox now confines seat writes as mitigation → follow-up for the write-scope grant itself.
- #79:
audit_loop --self-testexit 0, 15 vectors ✓ PASS. - #80/#81: not on disk, no wave scope → follow-up.
- #82:
make testruns all 11 suites, 257 OK ✓ PASS (no orphans: new suite wired into Makefile). - #83: 11 sweep tests in make test ✓ PASS. #84: 7 reconcile tests + #84 fixture exits 1 NEEDS-HUMAN-REVIEW ✓ PASS.
- #85: dirty-clone regen exit 2 ✓ PASS; archive fidelity (byte-identical _shared, lock unchanged) ✓ PASS.
- #86: roster sabotage exit 1 ✓ PASS. #87: stub sabotage exit 1 ✓ PASS.
- #88/#89/#90: not on disk, no wave scope → follow-up.
- #92: 69 envelope tests in make test ✓ PASS (incl. spec-mandated PUSH inversion).
- #93:
--source exec-director→ exit 2 "not a fleet member/role id" ✓ PASS; env-refusal + receipt matrix per M5 report (re-ran env half). - #94: table-defined (undeclared-binary probes) but no wave scope; gate-role corpus is role-fixed, live pi run needed → follow-up.
- #95: table-defined (TOML lint spellings), no wave scope → follow-up.
- #96: UNVERIFIABLE off-fleet (table says so; needs live fleet re-seed).
- #97: fabricated-tested sabotage exit 1 ✓ PASS; committed tree "Not tested"/[] ✓.
- #98: not on disk, no wave scope → follow-up.
- #99: ALLOW_DIRTY regen → verify exit 1 (DIRTY reject, 16 V13 + 16 V4) ✓ PASS.
- #100:
grep OPENRIG_VERSION docker/Dockerfile→ 0.6.13 ✓ PASS; render with missing declared pkg → exit 0 pps-only packages (pre-existing omission-tolerance in render-seat.py:364-374, untouched by M9; V12 names missing MCP binaries, pi_packages omission is silent) → recorded, follow-up candidate. - #101: not on disk, no wave scope → follow-up.
- #102: P3 spot-checks — stale "64 skills" prose (AGENTS.md/generator docstring vs 68 actual, pre-existing Wave-2/3 growth) noted; firecrawl minimal-profile standalone boot unverified (recorded M9 caveat); qdrant 1.15.3 / docker-android emulator_14.0 deltas vs upstream recorded (minimal-diff, no bump).
M10 PR attempt (push blocked — branch left ready)
git push -u origin remediate/audit-66-p0-p1-supplychain→ twice{"type":"permission.rejected","message":"Permission denied: shell"}(sandbox push guardrail; remote exists,gh auth statuslogged in — not a credential problem).- No PR opened. Full PR body text (spec format) + Gates/follow-up lines recorded in docs/reports/remediate-supplychain-implementation.md §PR.
- Shell host with push rights: push the branch, then
gh pr create --base mainwith that body. - Footer session-URL discrepancy noted: the stage spec file shows
.../session_014wevSWHET5eqHNVNTYZnx9while this wave's brief mandates.../session_014wevSWHET5eqHNVNTYZ9W; this stage uses the wave brief's URL consistently (commits + PR body).
Post-M10 semgrep hardening (own commit after 97a37ca)
semgrep_scanon the M9 generator flaggedtrailofbits.python.tarfile-extractall-traversalat theextractallcall. Source isgit archiveof the pinned commit (not attacker bytes), but hardened anyway: member-name validation (reject absolute/..) + per-membertf.extractinstead ofextractall. Rescan: 0 findings. Helper unit tests re-run 18/18 OK (incl. archive byte-fidelity). Fullmake test(257) +verify-rigs(29/0) confirmed green on the committed tree before this change; the change is extraction-mechanism-only (validated members, same bytes).
Catalog-vs-Dockerfile drift (found on-host, fixed in M9)
context7: catalognpm:@upstash/[email protected]vs Dockerfile4.4.2→ aligned to catalog.memory: catalognpm:@modelcontextprotocol/[email protected]vs Dockerfile1.0.0→ aligned to catalog.- Other 6 npm MCP packages + 3 pi-packages already agree.
- Decision (recorded per spec "or record why a list stays manual"): Dockerfile install lists STAY manual because (a) Dockerfile layers a builder/runtime split + conditional INSTALL_R2MCP toolchain that has no catalog counterpart, (b) uvx/docker/remote MCP servers need no image install, (c) fleet per-role pi_packages (13 distinct combos incl. pi-btw/pi-lens/pi-web-access/pi-mcp-adapter) are the single source consumed at render time by render-seat.py:352-374, the image bakes only the base triple. Compensating gate: V13 asserts Dockerfile versions == catalog/fleet pins exactly (drift fails closed).
remediate-lane-guard (#67 worktree-stale baked-path guard — Wave 5 micro-stage)
- HEAD confirmed pre-work:
git log --oneline -1→2b103db chore(remediate-66): re-bake generated leaves on canonical checkout. - The catch (verified, not trusted from summary): post-Wave-4 merge check found generated leaves baked an absolute
shellPathinto the Wave-4 worktree dir (.lane/trees/remediate-supplychain/scripts/seat-sandbox.sh), confirmed viagit showof the pre-fix blob. Re-baked on the canonical checkout in 2b103db; this tree's committed leaves all carry/home/john/Projects/heretek-rig-workspace/heretek-rigs/scripts/seat-sandbox.sh(no/.lane/— confirmed by the new gate scanning 153 leaves green). - Root cause:
render-seat.pyemitsshellPathasstr(Path(__file__).resolve().parent / "seat-sandbox.sh")— correct per checkout, checkout-dependent. V12 (verify-rigs.sh:1679-1683) only assertsendswith("scripts/seat-sandbox.sh"), so a worktree-stale absolute path PASSES while pi fails closed ("Custom shell path not found") at seat startup. Gotcha 5 (M3 tool-existence gate) therefore covers the source file but not the baked VALUE. - Guard location: NEW
== V14 ==block inscripts/verify-rigs.sh(after V13ok, before SUMMARY). V13 label was already taken by the supply-chain wave, so V14 was used; V1–V13 lines untouched (git diff= 32 insertions, 0 deletions). For every committedspecs/agents/*/*/runtime/pi-settings.json+rigs/*/agents/*/runtime/pi-settings.json, FAIL ifshellPathor anypackages[]value contains/.lane/; message names seat + file + key + offending value +#67 worktree-stale absolute path. - Green baseline (unmodified tree):
./scripts/verify-rigs.sh --check-only→SUMMARY: 29 checks passed, 0 failed, exit 0. - Green after guard:
SUMMARY: 30 checks passed, 0 failed, exit 0 ([PASS] Worktree-stale paths (#67) green: 153 committed pi-settings.json leaves carry no /.lane/ baked paths). - Red-proof 1 (shellPath sabotage, temp-edit +
git checkout --revert, never committed): planted/.lane/trees/evil/scripts/seat-sandbox.shascache-streaming-engshellPath →SUMMARY: 29 checks passed, 1 failed, exit 1 with[FAIL] V14/#67: seat cache-streaming-eng: ... shellPath holds worktree-stale absolute path ... (#67 worktree-stale absolute path — re-bake on a canonical checkout). Note the planted value still ends withscripts/seat-sandbox.sh, i.e. V12 passed it — the exact gap this guard closes. - Red-proof 2 (packages[] sabotage, same temp-edit/revert discipline): planted
/home/x/.lane/trees/evil/...aspackages[0]→ same exit-1 named gate onpackages[0]. - Revert verified:
git status --shortshows onlyM scripts/verify-rigs.sh; re-ran verify → 30/0. make test(untouched, proven):Ran 257 tests ... OK, exit 0; Makefiletest:runs 11 suites.scripts/generate-rigs.pyNOT run (no catalog edits in this stage — nothing to re-bake).
2026-10-30 — #91/#12 go exec residual + #11/#78 single-seat routes (Claude follow-up)
- Live finding (fleet-proofs runbook S3):
go build/go testwere policy-allowed but died onfailed to initialize build cache at ~/.cache/go-build: read-only file systembecause the jail binds/read-only.scripts/seat-sandbox.shnow setsXDG_CACHE_HOMEandGOCACHEunder the per-run scratch. Nothing persists between commands or crosses seats; each command rebuilds what it needs. Red-proof:tests/test_seat_sandbox.py::test_go_test_runs_in_seat_scopefails on the old wrapper with the exact live error and passes on the new one. - Remaining go limit (by design, not fixed):
go buildof a single main package writes its binary into the cwd, which is read-only in the jail, and-ois denied by the go command effect. Usego test ./...orgo build ./...over several packages (outputs discarded) as the compile proof.go mod initcannot creatego.modfrom bash (file roots bind existing files only); write it with thewritetool first. - #11/#78: OpenRig 0.7.5 (the pinned host toolchain) already ships
rig seat launch --fresh --stop,rig seat stopandrig seat set-cwd, andrig launchhelp no longer promises relaunch. Seat-heal/seat-repair used the re-seed + fresh-launch route live on 24 seats. Documented in USER_GUIDE "Refreshing or re-homing one seat", AGENTS.md, and the generateddocs/SEAT-WRITE-SCOPES.md(scripts/seat-scopes.py, drift-tested bytests/test_seat_scopes.py).set-cwdon a pi seat is not yet proven live.