gate: a deterministic test-integrity gate, so green CI must be earned - #107
Closed
open-coder-ai wants to merge 2 commits into
Closed
gate: a deterministic test-integrity gate, so green CI must be earned#107open-coder-ai wants to merge 2 commits into
open-coder-ai wants to merge 2 commits into
Conversation
docs/agentic-risk-coverage.md has carried this row honestly for weeks: ...an agent deleting tests or assertions to get green? agent-discipline (assertion_deletion: block) advisory today -- a deterministic test-integrity gate is a named catalog candidate, not yet a roadmap issue, so this row stays advisory until it is. It could not be anything else: all three existing kinds read only the added side of a diff, and test tampering is visible only in what a change takes away. This adds the missing primitive, GateContext.removed_lines(), and one kind built on it. test_integrity blocks three shapes, all deterministic and author-blind: a deleted test file, a net loss of assertions across the change, and a vacuous assertion (assert True, expect(true)) added in its place. The escape hatch is a pragma written on the line that removes the test, so an obsolete test can still go -- visibly, in the diff, where a human sees it. The net count is taken across the whole change rather than per file, which keeps a test split across two files from reading as a deletion. What it costs is a change that strips one file while adding to another; that is the right trade for a gate whose false positives would get it disabled. Patterns are policy data, not engine behaviour: the kind is language- agnostic and every language's idea of a test and an assertion arrives through params from .agents/policies/test-integrity/manifest.yaml. The gate runs on commit and in CI. CI is the half that matters for an inbound contributor, whose agent never ran a local hook. 7 behavioural tests over real git repositories, including the two that keep the gate adoptable: a refactor deleting an assert from application code passes, and a reviewed removal passes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014gwmBVUHSgohCLkNVqAR77
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: trueThanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Full-suite regression over the test-integrity work from ba00eca surfaced seven failures, all caused by this branch and now fixed: - Vendored .chock/bin/gate.py was stale against src/chock/gate/runner.py (re-vendored via `chock sync`). - The manifest's `on: [commit, ci]` declared a literal "ci" event that no runtime or schema recognizes -- CI coverage is derived from "commit" being present, per every other manifest and spec/gate-dsl.md. Fixed to `on: [commit]`. - src/chock/validation/schemas/manifest.hook.json's `kind` enum (structural JSON-schema layer, separate from KINDS/KIND_PARAM_SCHEMAS) never listed `test_integrity`, so any manifest declaring it failed validation. Added. - The policy shipped no evals/suite.yaml, tripping the eval_first check. Added six hand-authored cases (trigger/negative_trigger/ behavior/edge) -- not added to eval/derive.py's DERIVABLE_KINDS, since its params are open regexes over diff content, not an enumerable list like forbidden_ref's refs or dependency_allowlist's manifests. - spec/gate-dsl.md never documented the new kind's params. - Two files were unformatted (`ruff format --check` is part of CI though only `ruff check` was verified in the prior pass). Also, per chock-g1 T2-T5: - checks_gate_shape.py needed no code change (it already reads KINDS/KIND_PARAM_SCHEMAS); added tests confirming a test_integrity manifest validates and a bad param shape is rejected. - Confirmed test_integrity is absent from GATEWAY_ONLY_KINDS and RUNTIME_KINDS (it needs a git diff, so it has no gateway runtime). - .agents/policies/INDEX.md gets the new entry automatically from `chock sync`; docs/baseline-policies.md's guard table and declarative list are updated by hand (docs/policies/, docs/cli-reference.md and llms.txt don't enumerate individual policies). - docs/agentic-risk-coverage.md's test-deletion row moves from `advisory` to `enforced-at-commit`, backed by the tests above; no pre-tool-use tier is claimed since none exists. - CHANGELOG.md entry added. Found live while writing this commit: test_path_regex's directory branch matched any file under a `tests?/spec/__tests__` dir regardless of extension, so documenting the gate in spec/gate-dsl.md (this repo's own design-doc directory, not RSpec tests) with the worked example "assert True" tripped the gate's own vacuous-assertion check on itself. Fixed by excluding .md/.rst/.txt from the directory branch; regression cases added to both the eval suite and the behavioural pytest suite. Full suite: 1055 passed, 6 skipped. `ruff check .` and `ruff format --check .` both clean. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: Claude <noreply@anthropic.com>
open-coder-ai
force-pushed
the
claude/test-integrity-gate
branch
from
September 4, 2026 01:37
c0cd4e5 to
da66872
Compare
11 tasks
Owner
Author
|
Superseded by #108: same tree (confirmed byte-identical diff between branches), one commit amended to add a missing Generated by Claude Code Generated by Claude Code |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds a
test_integritygate kind: a deterministic check that blocks a change from winninggreen CI by weakening the tests instead of fixing the code. It catches three shapes: a
deleted test file, a net loss of assertions across the whole change, and a vacuous
assertion (
assert True,expect(true)) added in their place.chock: test-removal-reviewedon the removing line is the reviewed escape hatch.
This closes the honestly-carried gap in
docs/agentic-risk-coverage.md:Before → after (
docs/agentic-risk-coverage.md):The claim is scoped to exactly what the tests demonstrate:
enforced-at-commitandre-checked in CI on the PR head. No pre-tool-use tier is claimed — this gate has no
PreToolUsebinding.The engine work (already landed on this branch before this PR)
GateContext.removed_lines()— the missing primitive; the three existing kinds read onlythe added side of a diff.
_kind_test_integrity+ registration inKINDS(src/chock/gate/runner.py).test_path_regex,assertion_pattern,dummy_assertion_pattern,allowlist_pragma) insrc/chock/gate/schema.py..agents/policies/test-integrity/,on: [commit],action: block.tests/test_test_integrity_gate.py.This PR: full-suite regression, wiring, and three real bugs it surfaced
Only five test files were run before this PR (45 passed). Running the whole suite and the
whole lint tree surfaced seven failures — all caused by this branch, all fixed here:
.chock/bin/gate.py(the stdlib-only copy the git-hookactually executes) hadn't been re-synced against
src/chock/gate/runner.py. Fixed viachock sync.on: [commit, ci]— but CI coverage isderived from
"commit"being present (runner.py'sevent == "ci"branch), and noother manifest or
spec/gate-dsl.mdlists"ci"as a value insideon. Fixed toon: [commit].src/chock/validation/schemas/manifest.hook.json'skindenum (separate fromKINDS/KIND_PARAM_SCHEMAS, which already knew abouttest_integrity) still only listedthe three original kinds, so any manifest declaring
test_integrityfailed structuralvalidation before the per-kind param check ever ran. Added.
evals/suite.yaml; this one didn't,tripping the
eval_firstcheck. Added six hand-authored cases (trigger ×2,negative_trigger, behavior, edge ×2).
spec/gate-dsl.mdwas never updated with the new kind's params.ruff checkwas clean butruff format --check(alsopart of CI) was not.
test_path_regex's directory branch matched any file under atests?/spec/__tests__directory regardless of extension. This repo's own
spec/directory holds design docs,not RSpec tests — so documenting the gate's
dummy_assertion_patternparam inspec/gate-dsl.md, usingassert Trueas the worked example, tripped the gate's ownvacuous-assertion check on itself. Fixed by excluding
.md/.rst/.txtfrom thedirectory branch (a real improvement for any consumer, not a repo-specific hack); a
regression case was added to both the eval suite and the pytest suite.
Wiring into every place that enumerates kinds
src/chock/validation/checks_gate_shape.py— already readKINDS/KIND_PARAM_SCHEMASgenerically; needed no code change. Added tests confirming a
test_integritymanifestvalidates and a bad param shape is rejected (
tests/test_manifest_validation.py).src/chock/gate/schema.py::GATEWAY_ONLY_KINDS— confirmedtest_integrityis notgateway-only (it needs a git diff, which the gateway doesn't have).
src/chock/compile/emitters/mcp_gateway.py::RUNTIME_KINDS— confirmedtest_integrityisabsent (same reason);
chock syncemits nogateway-gate.jsonfor it, and nothing breaks.src/chock/eval/derive.py::DERIVABLE_KINDS— judgement call: not added. The existingderivers (
forbidden_ref,dependency_allowlist) synthesize cases from an enumerable list(branch names, manifest formats);
test_integrity's params are open regexes over diffcontent, with no such list to enumerate from. Hand-authored
evals/suite.yamlinstead.Docs and registry
.agents/policies/INDEX.md— picked up automatically bychock sync.docs/baseline-policies.md— added to the "Deterministic guards" table and thedeclarative-kinds list.
docs/policies/,docs/cli-reference.md,llms.txt— checked(
grep -rl "verify-dependency-exists" docs/ *.md llms.txt); none enumerate individualpolicies, so none needed changes.
CHANGELOG.md— entry added under Unreleased.Test evidence
test-integrity's own eval suite (chock check --only evals): 6/6 pass, score 1.00.Definition of done
chock check→ 0 errors, 0 warnings, 0 infoschock check --only matrixpasses; matrix updated in this PR if behavior changed (noinvariant IDs changed — 29 present before and after)
chock sync --repo . --checkclean (compiled artifacts match their manifests)chock check --only verifyclean (lockfile matches packs and compiled artifacts)pytest -qgreen; new checks have attack + ordinary-data testspytest acceptance/ -c acceptance/pytest.ini --rootdir=acceptancegreenartifact's schema changed)
test-integrityitself — itis brand new in this PR, still
0.0.1/draft, one "Initial" changelog entry per theconvention other pre-release policies use, e.g.
scan-secrets)ruff check .andruff format --check .cleanClaims
test-integrityuses theexisting
git-hook+ci-gatesurfaces (already inINSTALLED_SURFACES); no newsurface type was introduced, so nothing there needed a change.
docs/enforcement-surfaces.mddoesn't enumerate policies individually (checked), so nothing there needed a change.
docs/agentic-risk-coverage.mdis updated as shown above.Authority note
Per the dispatching brief (
chock-g1/W1), authorized paths for this work aresrc/chock/gate/,src/chock/validation/,.agents/policies/test-integrity/,tests/,docs/,CHANGELOG.md,.agents/policies/INDEX.md. Two touched files sit just outside thatliteral list, both load-bearing for "full suite green" (
chock sync's own generated diff, andthe doc fix a genuine test failure required):
spec/gate-dsl.md— the gate DSL reference;test_documented_gate_kinds_match_the_codefails without it (every other kind is documented there).
.chock/bin/gate.py,.chock/compiled/test-integrity/,.chock/coverage.json,.chock/registry.json,chock.lock— regenerated bychock sync, never hand-edited.Generated by Claude Code