Repository navigation
v0.58.0
[0.58.0] - 2026-09-20
Added
-
The DRI accepts the SPEC, and nothing irreversible lands without that acceptance.
hm spec_machine approve [--exempt]stamps a content-hash-boundapprovalinto the machine
SPEC (every authored field hashed, tooling fields excluded);approval-statusreports one of a
nine-row state table.schema_version: 3requires anirreversible_decisionslist
(IRR-NNN, five categories,source: spec|execute).specis now a judgment-gated autopilot
stage whose gate is derived from the SPEC, not the stage's claim;/hm:specends on
"Approve this SPEC and end interview";/hm:executeappends newly discovered irreversible
decisions (invalidating the approval); wrapup asks the DRI before landing, andwrapup_land,
worktree task-landandworktree finalize successrefuse withhold:lines — finalize
checks every worktree before merging any and finds SPECs from the branch diff. Pre-v3 SPECs
pass with a notice. The stamp records the flow; it does not prove a human. The hold fails
closed: a branch whose SPECs git cannot list holds, a task-land whose worktree is gone checks
the branch through a throwaway checkout, and a checkout's ownspec.dircannot point the
gate away from its SPECs (the base's dir is searched first; absolute or..values fall
back tospecs/). -
The proposal backlog gets a reader, and wrapup says so where you can see it.
.claude/memory/pending-proposals.mdhad one writer (wrapup Step 5.3) and no reader — 27 open
proposals, the oldest from 2026-05-17.hm proposals list|count [--open|--triaged]and
hm proposals summary(open-only,{"open": N, "oldest": date|null}) read it; an absent file
is an empty backlog, not an error. Wrapup's main loop now callssummaryat the head of
Steps 6 → 7.6and prints one line at five or more open proposals — not in Step 5.3, which runs
insidestage-delegatewhose output never reaches the operator. A failure of the call prints
one line and never halts (a pre-release plugin answersunknown module). -
High-recurrence failures reach every retrieving stage regardless of vocabulary.
hm memory_retrieveadds a labelledhigh-recurrencesection: the top--count-floor N
(default 3)[fail:*]entries by recurrence, with their own additive byte budget, so the
lexical section is byte-identical with the floor on or off. Excerpts keep the newest dated
blocks, so a later correction is what the reader sees. Measured: the topic "repair round broke
something new while the suite stayed green" returned(no entries matched)before (297 B) and
now surfaces the three most-recurring failures, includingfix-introduced-defect-passes-all-gates
(count:13) that it paraphrases (2649 B);worktree finalize stash mergegrows 8661 → 11013 B. -
/hm:executeloads failure bodies, throughhm memory_retrieve, instead of a
failures.mdhead-skim plus a slugrg— the one stage that writes code was the only one
reading slugs without bodies. -
project-knowledgeskill — capture code-absent project facts in the shared wiki
(SPEC-mission-context-loop S0).- The gap. Code-absent knowledge the DRI holds had no capture path: how an external
system behaves, an ops quirk, a correction of something previously believed. Claude Code's
default files "remember X" in machine-local auto-memory, which is invisible to git, Cursor,
Codex andmemory_retrieve. - Capture. When the DRI explicitly asks to remember a fact, or corrects a recorded one,
the skill searches first and writes a[wiki:fact]entry via the existinghm memory_md upsert-wiki. It reuses only a[wiki:fact]slug, and checks a new slug with the Grep
tool so it does not overwrite a fact the search missed. A correction replaces the entry and
ends withSupersedes: <old claim> (first recorded <date>), carrying the original capture
date forward. - What it refuses. It never records an inferred fact. It surfaces the CLI's stderr on
failure instead of falling back to auto-memory. Personal preferences stay in auto-memory. - Always-loaded pointer. A pointer of at most 300 characters in
CLAUDE.md,AGENTS.md
and.cursor/rules/harness.mdcroutes shared facts to the wiki even when the skill does not
trigger. The Codex copy names the skill file, because Codex starts skills only on mention. - wrapup 5.1 gains a 5.1.0 search-before-write step: it reuses a matching non-fact
slug and never reuses a[wiki:fact]slug, so a task summary cannot overwrite a DRI's
fact. - Templates. The wiki templates document the
factcategory and theSupersedes:line,
and/hm:helplists the skill. - Withdrawal (pre-registered). 28 days (UTC dates, inclusive) from the first
v*release
that ships it,scripts/measure_wiki_fact_window.pycounts[wiki:fact]subjects: ≥5 → S1
(subject files) becomes a candidate task; 0 → the skill and pointers are removed. It is
anchored as this repo'swiki_fact_entries_28doutcome and refuses to measure before the
window closes.
- The gap. Code-absent knowledge the DRI holds had no capture path: how an external
-
hm world assume addand content-fingerprint evidence locators. The assumption layer had
no way in — onlyobserve/resolveon existing records — sodepends_onand assumption
revisits had nothing to point at.addcreates a record (refusing an existing id or
conflict);--locator <path:A-B>onadd/observecites up to 40 lines of the checkout by
whitespace-normalised sha256 (never a commit SHA — wrapup records before its commit and
task-landsquashes), refused at record time if the citation does not exist.hm world gap --jsongainsassumptions,stale_evidence,moved_evidenceandneeds_revalidation;
hm world statusis unchanged and never reads cited files. Wrapup 5.7's assumption question
now lists stale assumptions first and offers "new — record an assumption" (four options at
most), showing the exactaddarguments and asking once more before writing; the
intent-layerskill lists the verb.add/observe/resolvenow hold a per-file
RMW lock (observe/resolvewrote unlocked before). Limitation: a locator detects drift in
cited code, not in claims about external tools (Claude Code, Codex,agy) — probe-backed
checks are a follow-up.
Changed
-
review_telemetrywall_time_msis optional (null= not measured, never0). The
review stage's own paragraph forbade interpolating it while the schema required it, so the first
emit of every round failed; the doc andPRIVACY.mdnow state the same contract./hm:plan
states thatstage_agent_ledger --barrier-indextakes an integer (type=int), as/hm:execute
already did, at every comprehension depth. -
hm world gap --jsongains awithdrawalblock (intent-layer-ops): the intent layer's
own kill criterion ("10 wrapups, no observed objective, no fired revisit → remove the layer")
was an uncounted skeleton comment; it is now measured from git history (filled_at, the
committer date of the oldest commit whose.claude/intent.yamlis filled in) and base-root
stage-spans.jsonlhm:wrapupstart events. A count that cannot be taken isnullwith a
reason, never a disguised0.status --jsonis unchanged — the block lives ingaponly.
Wrapup Step 5.7 prints one sentence whendueis true, reusing thegap --jsoncall the
outcome-measure question already makes (zero new Bash calls). -
Measured outcome evidence is now hash-referenced, not argv-copied:
hm world outcome measureused to write the full command argv (300–700 chars for some dogfood commands) into
every evidence row; it now writesauto: measure#<definition_hash[:12]> @ <sha> exit=0 cwd=<base|checkout>. The hash still pins which measure definition produced the number by
equality; the argv is recoverable viagit show <sha>:.claude/intent.yamlonly when
intent.yamlwas committed and clean at that sha. Existing rows are untouched. -
Sourced 10 of the 13
unsourcedplan-stage step-sensitivity classes (src/harness_maker/step_sensitivity.py):
a blind Codex classification against an external evidence bundle, reconciled with Claude's
own class-supporting citations under explicit ADR-003 §5 rules, gives each upgraded row a
falsifier and tracked excerpt instead of an inherited-from-a-neighbour guess. 3 rows stay
unsourcedwhere the two readings disagreed with no resolving citation.unsourced_step_share
moves 47.1% (40/85) → 35.3% (30/85); objectiveSOURCE-PLAN-STEPS's ≤31.8% target was missed
(a valid outcome under ADR-005 — the approved target of 20% is out of reach for a
plan-stage-only task). Registry,MATRIX-native-redundancy.mdrows/census and CLAUDE.md's
count all stay in agreement; render output is unchanged.
Fixed
memory_retrievereads wherememory_mdwrites. Without--memory-dirthe reader now
resolves the base root withmemory_md._memory_dir. Before, a stage whose cwd was a task
worktree read the branch copy ofwiki.md/failures.md, which never holds entries captured
mid-task (they are written to the base and folded only at land). An explicit--memory-dir
is unchanged, and thehigh-recurrencecount floor reads the same resolved root — so
/hm:execute's warm tier, which runs from the task worktree, now sees base-captured failures.
tests/unit/test_memory_retrieve_root.pyfails loudly if the default is lost.
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: respx-0.23.1, hypothesis-6.155.7, asyncio-1.3.0, anyio-4.13.0, 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 4.84s ==============================