Skip to content

feat(gate): add a script kind that runs a policy's own program - #154

Merged
jothimani-rajendran merged 1 commit into
mainfrom
claude/script-gate-kind
Sep 22, 2026
Merged

jothimani-rajendran merged 1 commit into
mainfrom
claude/script-gate-kind

Conversation

@jothimani-rajendran

Copy link
Copy Markdown
Collaborator

What

Adds kind: script to the gate DSL. The declarative kinds (content_regex, forbidden_ref, dependency_allowlist, test_integrity) answer questions a closed table can hold; a check that models flow through a method body (the motivating case is the Java security policy being moved into the catalog) cannot be written that way, and the only door for a script until now was the shell guard, which judges a command and never sees the file being written.

A script gate names a Python file under the policy's implementations/. The runner hands it the same material every declarative kind reads -- staged blobs at commit, the write at tool use and at the turn's end -- as JSON on stdin ({"event", "repo_root", "writes": {path: text}}) and carries back its verdict: exit 0 allows, exit 1 blocks with the script's own stderr/stdout as the reason. Any other exit code, a missing script, or no verdict within 30 seconds refuses rather than allowing what it never judged.

  • chock compile rewrites the bare name to the policy-relative path the git hook runs from (build.py).
  • chock check refuses a name that is not a bare .py file (schema pattern) and a declared script that is not shipped (checks_gate_shape.py).
  • The kind joins WRITE_PATH_KINDS, so it rides the existing pre-tool-use and stop fragments unchanged; a new emitter-stability fixture (stability-script) pins those bytes.
  • .chock/bin/gate.py re-vendored from runner.py; docs in spec/gate-dsl.md, docs/concepts.md, CHANGELOG.md.

Definition of done

  • chock check → 0 errors, 0 warnings; 5 infos, all pre-existing on main (unchanged by this PR)
  • chock check --only matrix passes (32 invariants); no behavior change to existing kinds, matrix unchanged
  • chock sync --repo . --check clean
  • chock check --only verify clean
  • Registry rescanned; no stale entries
  • pytest -q green: 1414 passed, 6 skipped (baseline 1394 + 20 new in tests/test_gate_script_kind.py, covering compiled path, commit/tool-use/stop verdicts, crash/missing/timeout refusals, emitter wiring, and validation)
  • pytest acceptance/ -c acceptance/pytest.ini --rootdir=acceptance green: 21 passed
  • Existing artifacts: none use script, so nothing to migrate; the only touched manifest is the new stability fixture
  • Touched manifests: new fixture only, at version 0.0.1; changelog entry added under Unreleased
  • ruff check . and ruff format --check . clean

Claims

  • No surface is described as enforcing more than it installs. INSTALLED_SURFACES is unchanged: the new kind emits through the same write and stop fragments the existing write-path kind uses, as the stability-script goldens show, and docs/enforcement-surfaces.md needed no change.

🤖 Generated with Claude Code

https://claude.ai/code/session_01CzNYfzP8ymU3r4JB9Sz8Ha


Generated by Claude Code

The declarative gate kinds answer questions a closed table can hold. A
check that models flow through a method body cannot be written that way,
and until now the only door for a script was the shell guard, which judges
a command and never sees the file being written.

`kind: script` names a Python file under the policy's implementations/.
The runner hands it the same material every declarative kind reads -- the
staged blobs at commit, the write at tool use and at the turn's end -- as
JSON on stdin, and carries back its verdict: exit 0 allows, exit 1 blocks
with the script's own words as the reason. Any other exit, a missing
script, or a script that gives no verdict within 30 seconds refuses rather
than allowing what it never judged.

`chock compile` rewrites the bare name to the policy-relative path the
git hook runs from. `chock check` refuses a name that is not a bare .py
file and a declared script that is not shipped. The kind joins
WRITE_PATH_KINDS, so it rides the existing pre-tool-use and stop
fragments; a new emitter-stability fixture pins those bytes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Claude <noreply@anthropic.com>
@jothimani-rajendran
jothimani-rajendran marked this pull request as ready for review September 22, 2026 11:56
@jothimani-rajendran
jothimani-rajendran merged commit 4bc126e into main Sep 22, 2026
19 checks passed
jothimani-rajendran added a commit that referenced this pull request Sep 22, 2026
Merging main brought #154 (kind: script) into the 0.9.3 section; the
heading is the release title, so it now names both features.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Jothi Mani Rajendran <250249270+jothimani-rajendran@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants