100%

Section 04 - mutation-gate hook (INV-6)

Goal

Close INV-6: a PreToolUse hook DENIES any Edit / Write / Bash-mutation of a manifest-distributed harness artifact unless an /improve-tooling sentinel is live. The workflow IS the edit path — there is no “quick edit just this once.” Promote “improve tooling, never work around” from discipline + reviewer-time flag to a HARD GATE.

Implementation Sketch

Mirror the proven thin-shell → python-guard deny-envelope pattern (scripts/create_plan_runtime/manual_invocation_guard.py + .claude/hooks/block-create-plan-manual.sh).

  • New scripts/harness_dist/manual_invocation_guard.py whose banned surface is Edit/Write/Bash-mutation against any path in the manifest-resolved distributed set (§01 fingerprint domain — resolve_includes × canonical_path_for). guard-check reads PreToolUse JSON on stdin, matches file_path/path/command, emits the deny envelope (permissionDecision: deny) unless a sentinel is live; always exit 0.
  • Use the SCOPED + EXPIRING sentinel shape (.claude/.route-unlock-active model in .claude/hooks/block-route-edits.sh:139-171) rather than a bare TTL — scoped to the touched paths, guarding against a stale blanket-allow marker.
  • /improve-tooling’s implement phase activates the sentinel (.claude/.improve-tooling-active) and deactivates at resume_original (mirror create_plan_runtime activate/deactivate). While live, edits to harness paths are allowed; otherwise denied with a redirect to “run /improve-tooling”.
  • New .claude/hooks/block-harness-edit.sh (thin pipe) registered in .claude/settings.json PreToolUse on Edit / Write / Bash.
  • BOOTSTRAP exemption: the gate depends on /improve-tooling already owning versioning (s-03). Until s-03 lands, the hook carries a bootstrap exemption so it does not block the edits that build the engine (workflow-ownership.md §3.3 bootstrap-window).
  • Lock the governance design: add a locked_designs: entry (scripts/improve_tooling_runtime/locked_designs.py model) whose touches: covers the versioning engine + mutation-gate hook + migration contract, so post-landing edits require a user-typed unlock. Add a threat-model.md §2 Tampering row + §4 mediation entry.

Spec & Rule References

INV-6 (mission). skill-control-contract.md §Skill Control Contract (sentinel = authorization). workflow-ownership.md §3.3 (bootstrap window). CLAUDE.md §Locked Designs. threat-model.md §2/§4.

Layer Coverage

Tooling-scope: L1-L11 N/A. L12 = the registered hook denying a real Edit to a harness path with no sentinel, allowing it with a live sentinel. pytest gate: scripts/harness_dist/tests/test_manual_invocation_guard.py (allow/deny/sentinel-TTL matrix, mirror the create_plan_runtime self-test shape).

Work Items

  • Add scripts/harness_dist/manual_invocation_guard.py denying Edit/Write/Bash-mutation of any manifest-distributed harness path unless an /improve-tooling sentinel is live.
  • Use the scoped+expiring sentinel shape; /improve-tooling activate/deactivate it across implement..resume_original; carry a bootstrap exemption until s-03 lands.
  • Add .claude/hooks/block-harness-edit.sh + settings.json registration; add a locked_designs entry covering the governance surface + threat-model.md §2/§4 rows.

Fresh intel (regenerated)

{ “schema_version”: 1, “target”: { “kind”: “plan-section”, “ref”: “installable-harness/s-0f191f30” }, “generated_at”: “2026-06-25T14:37:53.619342+00:00”, “graph_state”: { “head_sha”: “b74d6b9a”, “last_code_import_at”: “2026-06-25T14:34:26.259Z”, “embedding_stale”: false, “insights_stale”: false, “cpg_stale”: false }, “surfaces”: {}, “summary”: “intel-package[plan-section:installable-harness/s-0f191f30] agent-authored dossier”, “degraded”: false, “dossier”: { “objective_symbols”: [], “tiers”: {}, “agent_authored”: true, “difficulty”: { “class”: “routine”, “research_online”: false, “research_mode”: “auto”, “signals”: [], “plan_dir”: “/home/eric/projects/ori_lang/plans/installable-harness” } } }

(full dossier: mutation-gate-hook—s-0f191f30.intel.json)