Skip to content

v0.55.0

Choose a tag to compare

@github-actions github-actions released this 26 Aug 10:12
· 15 commits to main since this release

[0.55.0] - 2026-08-26

This release removes places where the harness reported success while checking
nothing. Three of its four changes are the same shape: a gate or a metric that
produced a green, confident answer without the input it claimed to be reading.
Nothing here is a new capability — verification_plan is the only addition, and
even it makes verification CONSISTENT rather than stronger: it aligns the local
gates to CI, and a project whose CI is weak now reproduces that weakness
faithfully.

Known and deliberately not fixed in this release: ci.yml's Pytest step carries
no -m "not advisory" filter while the measurement comment above it does, so
advisory tests run as blocking; test_runners plan's advice still names the
filter that step does not use; the 147 historically polluted ledger rows remain
on disk, neutralised by the exclusions file rather than purged; and
verification_plan reads GitHub Actions only, degrading elsewhere to the
example commands that were the status quo.

Removed

  • BREAKING for a harness not re-rendered since 0.53.0: lens_coverage check no
    longer accepts --diff-files / --rev.
    ADR-004 of PLAN-probe-envelope-contract
    set 0.55.0 as the sunset when it absorbed them, and this is that release — the
    expiry is enforced by the suite rather than by anyone remembering, so cutting this
    version is what removed them. The flags were dead on arrival: the repo-access probe
    they fed was deleted, and they were kept only so an older rendered review.md would
    not hit an argparse exit 2 at /hm:review Step 3 and lose the review. Rendered
    commands stopped passing them when the probe went, so a harness re-rendered at any
    point since is unaffected. One that has not been re-rendered since 0.53.0 will now
    see that exit 2 — run /harness-maker:make --update.

Added

  • hm verification_plan {show,commands} — the gate commands are now DERIVED from the
    project's CI, not guessed.
    /hm:verify and /hm:wrapup used to ship EXAMPLE commands
    (mypy --strict src/, ruff check src/ tests/), which are a guess about someone else's
    repository; the dangerous direction of that guess is NARROWING, because a local pass that
    checks a subset produces exactly the same green output as one that checks everything. This
    harness's own stages checked src/ while its CI checked src tests, so every type error
    in test code was structurally unreachable locally — two consecutive commits shipped a red
    CI through the gap. The reader keeps push/pull_request workflows, reports one blocking
    command per gate kind, carries continue-on-error through so an advisory CI step never
    becomes a blocking local gate, lists both the commands it did not select and the ones it
    could not classify, and degrades EXPLICITLY with a reason so an empty plan cannot read as
    "this project has no gates". GitHub Actions only; anything else falls back to the previous
    examples, which is the status quo rather than a regression.

Fixed

  • The Production find-unbound gate can now fail. It never had. --collect-only
    prints node ids at exactly verbosity -1, and _pytest_collect_nodeids passed its own
    -q on top of this repo's addopts = "-q" — landing on -2, where pytest prints
    per-file counts (tests/e2e/foo.py: 2) instead. Nothing in that form contains "::",
    so the parse always yielded nothing, every AC looked un-collectable, and find-unbound
    reported OK over genuinely unbound work. The helper now resets addopts to pin the
    verbosity it parses, and treats rc 0 with zero parsed node ids as could-not-adjudicate
    rather than as an empty suite — pytest signals a real empty suite with rc 5, so rc 0
    with unreadable stdout is our own read failure. That second half is independent of the
    first and holds for any future output-format change. Every existing collect test built
    a sandbox with no pyproject.toml, so none of them could reproduce the composition
    that killed the gate; the new one builds a repo that carries it, and asserts as a
    precondition that the naive parse still finds nothing there.

  • CLAUDE.md's second-opinion loss-rate guidance now names the shipped reader
    (hm verifier_discrimination report + .claude/observability/.ledger-exclusions.json)
    instead of prescribing a hand formula. A hand calculation over the raw ledger reported
    codex at 61.3% where the reader reports 2.15% — a 30x error, because 147 of 375 rows were
    pytest fixture writes the exclusions file already names. A differential test runs the
    documented command as a subprocess over a fixture ledger and compares its per-model
    loss_rate to the shipped reader's own output.

  • worktree._cli_span_end now copies git_branch/task_slug from the span's own start
    when the caller has a session id. Every one of the 109 end rows in the live ledger had
    nulled both fields, so a slug-keyed join over stage-spans.jsonl always returned zero spans.

  • wrapup_receipt._confined accepts an absolute path iff it resolves inside the repo root,
    instead of rejecting every absolute path outright (it was firing on truthful delegate
    receipts reporting documents written from inside a .worktrees/<slug>/ checkout).
    WrapupReceipt gained two fields observed in production delegate receipts, and the
    stage-delegate template now states the exact key set and path form expected in return.

  • tests/unit/test_run_classify.py's fixture no longer hardcodes an absolute date. The old
    fixture pinned timestamps to 2026-07-26 while _cmd_boundaries falls back to a 30-day
    window, so on 2026-08-26 every turn fell outside the window and all seven tests failed —
    a time-bomb that was green on the day it was written and silently failed a month later.

Changed

  • CLAUDE.md shrunk from 624 to 392 lines (Production ceiling is 500) by relocating two
    procedural blocks verbatim into docs/reference/implementation-patterns.md and
    docs/reference/pre-change-checklist.md, with a resolving pointer left in their place.
    Nothing was compressed or reworded.

Boundary tests (advisory)

Layer 1 of PLAN-test-fidelity-gap. Pure parser checks; advisory only.

Status: ✅ PASS

============================= test session starts ==============================
platform linux -- Python 3.12.14, pytest-9.0.3, pluggy-1.6.0
rootdir: /home/runner/work/harness-maker/harness-maker
configfile: pyproject.toml
plugins: anyio-4.13.0, asyncio-1.3.0, hypothesis-6.155.7, respx-0.23.1, xdist-3.8.0
asyncio: mode=Mode.STRICT, debug=False, asyncio_default_fixture_loop_scope=None, asyncio_default_test_loop_scope=function
collected 50 items

tests/integration/test_boundary_codex_toml.py ............               [ 24%]
tests/integration/test_boundary_cursor_mdc.py .......                    [ 38%]
tests/integration/test_boundary_harness_yaml.py ........                 [ 54%]
tests/integration/test_boundary_hooks_json.py .........                  [ 72%]
tests/integration/test_boundary_meta.py .......                          [ 86%]
tests/integration/test_boundary_settings_json.py .......                 [100%]

============================== 50 passed in 5.52s ==============================