Skip to content

feat(kit): v2.4 the gate reads structure, not prose - #20

Merged
David405 merged 2 commits into
masterfrom
feat/kit-gates-002-tighten-gate
Aug 29, 2026
Merged

feat(kit): v2.4 the gate reads structure, not prose#20
David405 merged 2 commits into
masterfrom
feat/kit-gates-002-tighten-gate

Conversation

@David405

Copy link
Copy Markdown
Owner

Summary

Adds the kit's third layer. Rules and skills are instructions to a model that can misread them under load. A gate is a fact that exits non-zero. Kit → 2.3.0.

Before this, every "gate" in the kit was self-reported: AGENT_PROCESS asked the agent to run commands and nothing confirmed it, so an executor could set PENDING_REVIEW without running anything. Status drift went unnoticed four times this month across two repos.

Contract: skills/.harness/contracts/KIT-GATES-001.md — and as of this PR it is in the diff, which is the point of one of the changes below.

Prediction becomes recording

The contract form asked for "Expected RED output". Expected. A prediction written before anything ran, never compared to reality. It becomes three recorded blocks: RED (real command, real exit code, the assertion message, timestamp — captured before EXECUTE), BASELINE (suite before), GREEN (same commands after, counts compared).

A test that never failed proves nothing. It may be vacuous, or already passing. A RED that failed on an import error proves the test file is wrong, not that the behaviour is absent.

Slices with no ERD are covered by the same gate, and it tightens rather than relaxes: without a design document each success criterion must be expressible as a failing test before work starts, or the contract is not approvable. That was already the kit's law — the RED artifact makes it executable.

scripts/verify-harness.sh

Nine checks on discipline rather than code. The three that matter most: every [GROUNDED] path must exist (catches invented files, the commonest contract hallucination), the diff must be contained by the impact map (undeclared files are how regressions arrive), and RED must have failed on an assertion.

Contract-dependent checks skip visibly when no contract is reachable, so the script is useful mid-adoption; --strict turns skips into failures.

Criterion 2 — demonstrated, not asserted

The contract required proving the gate fails, not claiming it. Four defects injected and restored:

Injected Gate output Exit
status: "BOGUS" status 'BOGUS' not in legend 1
verify: "tested" verify does not look like a command 1
PENDING_REVIEW, no contract PENDING_REVIEW without a contract: GHOST-001 1
Rule with no frontmatter rules with bad frontmatter 1

And it exits 0 against harness-kit itself.

CI is the unforgeable layer

.github/workflows/harness.yml runs the gate and re-runs the contract's own VERIFY block, so a claim that verification passed locally stops mattering. One script, invoked from CI and optionally from an editor hook — never reimplemented per surface, or the layers drift and you get a gate that passes locally and fails in CI for reasons nobody can reproduce.

Contracts are now tracked

harness-review §0 tells a reviewer to grade a PR against its contract, and the contract was gitignored — invisible to the reviewer, invisible to CI, and (observed this week) invisible to the author in Finder and the editor sidebar. Checks 6–8 need to read it, so this stopped being cosmetic.

Seven existing contracts land in git with this commit. STATE.md, drafts and PR bodies stay local.

This needed more than a .gitignore edit: the legacy rule .harness/ is unanchored, so it matched skills/.harness at any depth and kept contracts ignored regardless of the new negation. Found with git check-ignore -v, anchored to /.harness/ — its intended root-only meaning.

Deviations

The gate found a false positive in itself. On first run, check 6 reported master and ef393c3 as missing paths — branch names and commit SHAs are also backticked on [GROUNDED] lines in the Branch section. Narrowed to tokens containing / or carrying a known extension. Caught by dogfooding before shipping, which is the argument for making criterion 1 "exits 0 against this repo".

And it caught the sprint that introduced it. Tracking contracts pulled six pre-existing contract files into the diff which the impact map had not declared. Scope containment reported them as undeclared and exited 1. The remedy was to amend the contract, which is the intended behaviour — not to relax the check. First live catch, on its own PR.

Q1–Q4 as executed

Contracts tracked · scope containment blocks (the remedy is amending the contract; warning-only gates get ignored) · BASELINE for behaviour changes only · CI shipped as a kit file adopted through the skill tree rather than written into a consumer's .github/.

Known limit

A vacuous test (expect(true).toBe(true)) survives every check here. Mitigations in ascending cost: the assertion-shaped RED requirement; reviewing the test at contract approval, before EXECUTE, when changing it is cheap; and mutation testing, which is documented as an option and deliberately not a default.

VERIFY

20/20 green — gate executable, POSIX-clean, exits 0 on this repo; CI present and invoking the script; "Expected RED output" gone and the recorded blocks present; never-failed and no-ERD rules stated; AGENT_PROCESS and REVIEW wired to the same script; contracts tracked while STATE.md stays ignored; 2.3.0 across README, build script and BOOTSTRAP; Appendices R and S; bootstrap regenerates; FEATURES.json parses.

🤖 Generated with Claude Code

Adds the third layer. Rules and skills are instructions to a model that can
misread them under load; a gate is a fact that exits non-zero.

scripts/verify-harness.sh checks discipline rather than code: ledger integrity,
every PENDING_REVIEW has a contract, skills and rules will actually load, every
[GROUNDED] path in the contract exists, the diff is contained by the impact
map, and RED was recorded and failed on an assertion. Contract-dependent checks
skip visibly when no contract is reachable; --strict turns skips into failures.

The contract form asked for "Expected RED output" — a prediction, written
before anything ran, never compared to reality. That becomes recorded RED,
BASELINE and GREEN blocks. A test that never failed proves nothing: it may be
vacuous or already passing, and one that failed on an import error proves the
test file is wrong rather than the behaviour absent.

Slices without an ERD are covered by the same gate, and it tightens rather than
relaxes: if you cannot write a test that fails today you do not have a
falsifiable criterion, and the contract is not approvable.

CI re-runs both the gate and the contract's own VERIFY block, so an agent's
claim that verification passed stops mattering. One script, invoked from CI and
optionally from an editor hook, never reimplemented per surface.

Contracts become tracked. The review process grades a PR against its contract
and CI cannot check a file it cannot see; the same invisibility hid contracts
from Finder and the editor sidebar. Session state, drafts and PR bodies stay
local. This also anchors the legacy .harness/ ignore rule, which was unanchored
and matched skills/.harness at any depth.

Adds Appendices R and S and bumps the kit to 2.3.0.

Contract: skills/.harness/contracts/KIT-GATES-001.md
Two findings from the gate's own first run against this repo.

Check 6 was guessing. The v2.3 patch accepted a backticked token as a path only
if it contained a slash or a known extension, which silently skipped real paths
like Makefile and checked things that were not paths at all. A check that
silently skips is worse than one that fails loudly. It now locates the Impact
map section, reads to the next heading, and takes the first cell of each marked
table row. Unparseable marked rows fail; bullet-list impact maps skip visibly.

That only works because the artifact is unambiguous, so the contract form now
states that [GROUNDED] belongs to the impact map alone, and the Branch section
example no longer carries a marker. Structure the parser can read position from,
instead of prose it has to interpret.

Check 10 closes the drift the ledger check already covers. FEATURES.json rot was
caught; the same rot in STATE.md was invisible, since the gate only asked whether
the named contract existed. An inbox entry naming a feature already PASS now
fails.

The first implementation of check 10 also flagged four ids that were not rot at
all: an audit belonging to another repo, two pieces of planned work deliberately
named, and a filename the regex matched inside. That half was noise, so it is
gone; the check now fires only on ids present in the ledger and already PASS.

Bumps the kit to 2.4.0.

Contract: skills/.harness/contracts/KIT-GATES-002.md
@David405
David405 merged commit 204d65c into master Aug 29, 2026
1 check passed
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.

1 participant