bareloop 0.14.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,224 @@ feature lands, **patch** = docs, fixes, scaffolding.
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.16.0] — 2026-08-30
11
+
12
+ ### Added
13
+
14
+ - **`PROMPT_COMMIT_RANGE` covers every commit of a direct push (PRD #2b, #8)**:
15
+ `scripts/prompt-commit-check.mjs` now honours an env var of that name (`--range` mode
16
+ only — a commit-msg hook's `--message-file` path is never redirected by a stray env
17
+ var), which supersedes `--range` and needs no `HEAD~1` fallback of its own.
18
+ `.github/workflows/ci.yml`'s `npm test` step sets it to `github.event.before..sha` on
19
+ push events, so a linear multi-commit direct push to `main` is inspected whole instead
20
+ of the local `HEAD~1..HEAD` fallback re-covering only the last commit. An unresolvable
21
+ env range (a 40-zero `github.event.before` on a brand-new branch push) is reported and
22
+ falls back to the `--range` arg's own path, including its existing main-push fallback.
23
+ Same option-shaped-value guard as `--range` (a value starting with `-` is refused before
24
+ it reaches `git`). Premise measured on `origin/main`'s own reflog (two 3-commit linear
25
+ pushes on 2026-08-24, one carrying a prompt-register change the `HEAD~1` fallback would
26
+ have skipped); 3 new CLI tests, each proven failing before the fix. **CI-proven
27
+ 2026-08-30**: a branch-birth push (40-zero `before`) fell back and checked 5 commits
28
+ (CI run 33314883771); the next push used the real range `7e975b3..f0c3199` and checked
29
+ exactly 1 (run 33314899690).
30
+ - **Green-class runs mint a registry row, born released** (PRD open item #16,
31
+ `src/reuse.js`'s `writeRunGreenRow`): the fourth refusal (`credit-not-held`) is dropped —
32
+ a mechanical `green` run now mints its registry row at run end exactly like `soft-green`
33
+ does, but unheld: `greenParts` already keys the hold on `quarantinesCredit(verdictType)`
34
+ (`src/bridges.js:372`), so no bridge/door code changed. `door accept` on an unheld green
35
+ row records the disposition and releases nothing — it no longer dies `no-row-for-run`;
36
+ that terminal is reserved for a run that truly earned no row. `scripts/run-u.mjs`'s
37
+ registry line now prints `HELD`/`RELEASED` by class instead of `HELD` unconditionally,
38
+ and its door credit readout distinguishes a genuine release from a repeat `accept` on an
39
+ already-released row (`recordDoor` returns `released: false` on a same-decision repeat —
40
+ the wording now branches on `quarantinesCredit(spec.verdictType)` rather than claiming a
41
+ fresh release every time). 4 new/updated tests (2 proven failing before the fix),
42
+ including a soft-green regression guard (still born `HELD`) and the still-refusing
43
+ no-row-for-run case.
44
+
45
+ ### Changed
46
+
47
+ - **`bareloop.context.md` leads with the shipped design** (PRD #14): the header states the
48
+ v0.15.0 contract first — `green` + `soft-green`, the judged floor and calibration gate,
49
+ the review door (`accept`/`rerun`/`pause`) that never changes the loop's own verdict —
50
+ and demotes `hitl` to a LEGACY block: still admitted in code (`VERDICT_TYPES`,
51
+ `human-confirms`, `hitl-pause`/`hitl-decision-red`), retired by design (PRD v1.71),
52
+ removal a future breaking change. Six inner passages that still called `soft-green`
53
+ "locked" or `hitl` "the forward path" now state the shipped fact.
54
+ - **The authorjob no-repo refusal message** (`src/authorjob.js`) no longer says a judged or
55
+ human close is "declared-but-locked" — `LOCKED_CLASSES` has been empty since v0.12.0; it
56
+ now says what is true: this authoring flow drafts code-genre closes against a git seed
57
+ only.
58
+ - **4 `jobs/*.json` description paths repointed, docs reorg** (PRD #13): the two preregs
59
+ living under `docs/logs/` (`TESTGEN-PREREG.md`, `REUSE-LIFT-CONTRAST-PREREG.md`) moved to
60
+ `docs/product/` beside the other eight; `docs/index.md`, the one live `FINDINGS.md` link
61
+ and `scripts/gen-mutants-testgen.mjs`'s prereg string follow. The four job descriptions
62
+ that still cited the pre-reorg `docs/02-experiments/*-PREREG.md` path now cite the real
63
+ files — each job's signed hash flips and re-signs at its next run. `docs/archive/` and
64
+ CHANGELOG history left as written.
65
+
66
+ ### Fixed
67
+
68
+ - **`--range`-only CLI tests no longer leak an ambient `PROMPT_COMMIT_RANGE`**: the six
69
+ tests exercising `--range` in isolation now pass `PROMPT_COMMIT_RANGE: ''` explicitly, so
70
+ a resolvable ambient value (as CI's own `npm test` step now sets on every push) can never
71
+ silently route them onto the env-range path they don't exist to prove.
72
+
73
+ ### Ruled (no code change)
74
+
75
+ - **Accept's re-proof wall governance** (PRD #15, hamr, 2026-08-30): the door-accept
76
+ re-proof runs unclocked, on the condition it stays mechanical
77
+ (`mechanicalStages()` only, `src/reviewdoor.js:213`) — never a judged floor, never a
78
+ person. A check is never bounded (W-2); any future non-mechanical re-proof is a new
79
+ arbiter question.
80
+ - **`hitl` cleanup deferred** (PRD #21, hamr, 2026-08-30): `hitl` stays admitted in code
81
+ (retired by design only) until hamr decides between finishing the retirement (delete the
82
+ class, the stage kind, the two terminals, migrate any job using it — a breaking rung with
83
+ its own release) or keeping it reopenable. Unscheduled either way.
84
+
85
+ ## [0.15.0] — 2026-08-27
86
+
87
+ ### Added
88
+
89
+ - **Generic run replay** (PRD build-list #6): `replayRun`/`formatReplay` (`src/replay.js`)
90
+ reconstruct one run's whole story from its spine JSONL + gate-audit sidecar. The single-run
91
+ report is a signed layout (hamr, 2026-08-25): a header block (`goal:`/`shape:`/`signed:`/
92
+ `branch:`/`outcome:`/`spent:`, absent fields printing the literal `none recorded`, never
93
+ blank or a fabricated `0`), a `TIMELINE (steps)` or `TIMELINE (iterations — loop-shape run)`
94
+ section with its own column-header row and per-row time/cost (wall, `$` — a `null` `costUsd`
95
+ anywhere in a row's window makes that row's spend `unknown (N unpriced rounds)`, never `0` or
96
+ a partial sum stamped exact) and a `↳ tripped:`/`↳ close:` line under any row an escalation or
97
+ close fell inside, a `CLOSE` section (never omitted — `none — the run ended before any close
98
+ ran` when nothing ever closed; picks the run's REAL final close by seq, never by record type —
99
+ an early `outer-close` precheck reading red must not shadow a LATER fix-loop close-verdict that
100
+ went satisfied), `ENDING` (last record + 3 before it, plus an out-of-window escalation), the
101
+ `BEHAVIOUR` block, and a `MEMORY-CACHE` line always printed (`not armed on this run` when
102
+ absent — absence is never silent). Stop reason is `category — decision — detail` off the last
103
+ escalation, so a run's actual failure text (a TLS "bad record mac", a specific mypy error)
104
+ rides onto the report instead of just the generic per-category decision prose. A step id that
105
+ recurs after a replan is split per OCCURRENCE, never merged into one pooled row. `--all <dir>`
106
+ is name-agnostic (a spine is identified by a `job-start`/`run-start` record in its content,
107
+ never a filename convention) and prints a fixed-column, ALIGNED table (never CSV) — `id job
108
+ shape outcome spend wall steps reason`, `reason` built from `detail` only (never `decision`,
109
+ cut at 60 chars) — flagging any non-spine `.jsonl` as `<name> not-a-spine` rather than dropping
110
+ it. A RESUMED run's `job-end.spentUsd` is a CHAIN total (prior legs folded in) that can never
111
+ equal this one file's own rounds (measured: `u-msf70nei` header `$5.3389` vs its own 55 rounds
112
+ summing to `$1.2127`) — the header now prints both, each labelled, plus a `resumed:` line
113
+ (keyed on `job-start.priorSpentUsd`, never on the narrower `resume-seed` record alone — 4 real
114
+ archived runs carry a real fold with no resume-seed record at all). A non-resumed run's own
115
+ spend disagreeing with its summed rounds is a genuine finding and prints as a `MISMATCH`, never
116
+ hidden (measured: 0 of the archive's non-resumed runs trip it). `--all` marks a resumed row
117
+ with a trailing `*` and one footnote line when the listing holds any. Reuses `runBehaviour`/the
118
+ `memory-cache` readout rather than reimplementing either. Reads only, mints no verdict, writes
119
+ nothing to the spine. `job-start` (`src/run.js`) now also carries `verdictType` (the spec's
120
+ required verdict class) and `model` (when the shell-owned provider binding itself carries one)
121
+ — PRD TODO #20, blessed verbatim by hamr the same day. The header prints `class:`/`model:`
122
+ right after `shape:` (`not recorded (pre-F117 spine)` / `not recorded` on an older archive or
123
+ a provider with no `.model`), and `--all` gains `class`/`model` columns (`model` kept FULL,
124
+ never truncated).
125
+ - **Prompt-commit shape — a check, not convention** (PRD build-list #5, TODO #8, Q9 answered
126
+ by hamr 2026-08-25): a commit that changes a prompt register (a model-facing
127
+ system/strategy/instruction string a worker or judge reads) must now say, in its own
128
+ message, three labelled things — `Failure:` what caused the change, `Addresses:` what it
129
+ addresses, `Corrects:` what it corrects. `src/promptregisters.js` (`PROMPT_REGISTERS`,
130
+ `isPromptFile`, both exported from `bareloop`'s root) is the ONE inventory: 7 files carry
131
+ real prompt content (`src/authorscout.js`, `src/authorflow.js`, `src/judged.js`,
132
+ `src/cardauthor.js`, `src/readshim.js`, `src/tools.js`, `src/planrun.js`) — more than double
133
+ the 8 named consts a first grep found, once module-private consts and inline
134
+ template-literal prompt builders (`scoutPrompt()`, `cardCasesPrompt()`, `locatePrompt()`,
135
+ `strategyFor()`) are counted; the check is file-scoped precisely because a const-scoped one
136
+ would have silently missed those. Enforcement is LOCAL ONLY — wired into `npm test`
137
+ (`scripts/prompt-commit-check.mjs --range origin/main..HEAD`), never into any
138
+ `.github/workflows/*` file (ask-first, untouched); an unresolvable range (no `origin`, no
139
+ fetch) is a printed SKIP at exit 0, never a violation. Pure decision logic lives in
140
+ `scripts/promptcommitlib.mjs`, neither of which ships (`scripts/` is outside
141
+ `package.json`'s `files`). hamr's same-day addition: the `Failure:` line must also cite
142
+ the RUN that caused the change (`run <id>` / `run u-<id>`, `\brun\s+(u-)?[a-z0-9]{6,12}\b`
143
+ — alphabet/length measured against 231 real archived spine ids, every one exactly 8
144
+ lowercase-alnum chars), failing with a distinct message
145
+ (`FAILURE_NEEDS_RUN_REF`) when absent; format only, never checked against a real spine
146
+ file.
147
+ - **Run→code stamp** (F118, the parked half of the same day's prompt-commit build, closed
148
+ same day on hamr's go): the prompt-commit check closes commit→run; this closes run→code.
149
+ `src/codeversion.js`'s `codeVersion()` is a pure, $0, no-shell reader — `version` from
150
+ bareloop's own `package.json`, `sha` from `.git/HEAD` (loose ref, falling back to
151
+ `packed-refs`) ONLY when a `.git` directory exists at the package root (a dev checkout;
152
+ an npm install has none), `dirty` always `null` (uncommitted-changes state cannot be
153
+ known without a shell — reported as unknown, never faked as `false`). `job-start`
154
+ (`src/run.js`) now also carries `code: {version, sha}`. `replayRun`/`formatReplay`
155
+ (`src/replay.js`) read it: a `code:` line right after `model:` — `bareloop 0.14.0 @
156
+ 43f2812` / `@ sha unknown` / `not recorded (pre-F118 spine)`; no new `--all` column
157
+ (hamr's index is already full). The library never grows a shell seam to answer this —
158
+ `run` stays the one locked verb.
159
+ - **Replay surfaces transport retries and floor reasons** (F119, live-proven the same day
160
+ a real run — `u-mt8yk53k` — fired the retry seam twice): `replayRun`/`formatReplay`
161
+ window `transport-retry` records into the step/iteration occurrence they fell inside
162
+ (same `seq` windowing as `worker-round`), printing `↳ transport retry ×N (recovered|not
163
+ recovered|partially recovered) — <error>` under that row; a retry outside every window
164
+ prints as `transport retries outside steps: N` under the `TIMELINE` header instead. The
165
+ header's `spent:` line, whenever `spendComplete:false`, now appends `· floor because:
166
+ <reason(s)>` — derived from the spine, never guessed: `transport retry ×N`, `unpriced
167
+ round(s)`, `cut mid-call`, `stall`, `prior leg floor`, every cause that shows real
168
+ evidence, or `floor (reason not in spine)` when none can be derived. `--all` adds no
169
+ column: a run carrying any retry gets ` ⟲N` appended to its outcome word (same posture
170
+ as the resumed `*`), with one footnote when the listing holds any. Report-only — reads
171
+ existing `transport-retry`/`wall-halt`/`stall`/`job-start` records, writes nothing.
172
+
173
+ ### Fixed
174
+
175
+ - **Leaked tmp dirs from `npm test`** (same class that filled `/tmp` tmpfs on 2026-08-25 and
176
+ blocked a build): `tests/codeversion.test.js`'s real-worktree test tracked only the `wt`
177
+ subdirectory passed to `git worktree remove`, never the `mkdtemp`-created parent, so every run
178
+ left an empty `codeversion-worktree-*` dir behind; its `after()` now also prunes stale worktree
179
+ metadata when `remove` fails and `rmSync`s the tracked dir unconditionally, plus the mkdtemp
180
+ parent is now itself tracked and removed. `tests/ralph.test.js`'s cwd-threading test created a
181
+ `ralph-cwd-*` repo with no cleanup at all, and its cwd-relative-close test likewise leaked a
182
+ `close-cwd-*` and a `close-cwd-other-*` dir per run; added a per-test `after(() => rmSync(...))`
183
+ for each, matching the file's existing top-level cleanup pattern.
184
+ - **`codeversion.test.js` false-red on PR checkouts** (F118 addendum): the HEAD-sha test's own
185
+ precondition assumed a symbolic ref, but `actions/checkout` leaves a PR checkout's HEAD
186
+ DETACHED at the merge commit, so the precondition threw before the module under test ever
187
+ ran — `src/codeversion.js` itself already handled the detached case correctly. Test-only fix:
188
+ the precondition now resolves a bare 40-hex `.git/HEAD` the same way `codeVersion()` does, plus
189
+ a new deterministic fake-package-root test that exercises the detached case without depending
190
+ on the checkout's own HEAD state.
191
+ - **Review of PR #23 (2026-08-26), 7 items fixed**: (1) `replayRun`'s spend totals
192
+ (`src/replay.js`) counted only `worker-round`, silently dropping a close's own `judge-round`
193
+ spend and native `worker-turn` attribution out of every total — now filters on the canonical
194
+ `SPEND_RECORD_TYPES` (newly exported from `src/ledger.js`), including the per-step window,
195
+ which no longer requires a `.phase` match for records (like `judge-round`) that never carry
196
+ one. (2) `scripts/promptcommitlib.mjs`'s run-reference regex accepted plain prose ("run
197
+ failed" satisfied its `{6,12}` margin outright) — tightened to the measured exact shape
198
+ (`{8}`); a proposed additional per-id digit requirement was investigated and REJECTED (23 of
199
+ 130 re-sampled real archived ids carry no digit, `msdsmkid` among them). (3)
200
+ `src/codeversion.js` read `sha: null` inside any real git worktree (`.git` there is a FILE,
201
+ `gitdir: <path>`, not a directory) — now resolves the pointer file and the worktree's
202
+ `commondir` to find HEAD/refs correctly. (4) `replayRun`'s `resumed` flag missed a genuine
203
+ $0-floor resume (`priorSpentUsd: 0` is still a real fold per `src/run.js:328`'s own doctrine)
204
+ — now keys on the field's presence, not `> 0`. (5) `scripts/run-replay.mjs --all` opened
205
+ every run's gate-audit sidecar despite never using the fields it feeds — no longer opens it
206
+ in `--all` mode (`--all` output on `aurora-u-bareloop` confirmed byte-identical before/after).
207
+ (6) the steps/iterations windowing logic in `replayRun` was duplicated inline twice — extracted
208
+ into one shared `buildOccurrenceMetrics` helper (replay output on `u-msdsmkid`, `u-msf70nei`,
209
+ `u-mt8yk53k` confirmed byte-identical before/after). (7) `npm test`'s prompt-commit check
210
+ (`origin/main..HEAD`) inspects NOTHING after a direct push to main, because the push itself
211
+ advances `origin/main` to match `HEAD` — `scripts/prompt-commit-check.mjs` now falls back to
212
+ `HEAD~1..HEAD` on that exact condition and prints that it did; a multi-commit direct push
213
+ still only re-covers the last commit (needs `github.event.before`, a `.github/` edit — out of
214
+ scope here, ask-first).
215
+ - **Release-gate findings (2026-08-27)**: `scripts/prompt-commit-check.mjs`'s `--range` value
216
+ was passed to `git rev-list` positionally with no way to disambiguate it from an option — an
217
+ option-shaped value (e.g. `--output=<path>`) was parsed by git as its own flag (verified: a
218
+ `--` separator does NOT fix `rev-list`, unlike `show`/`diff-tree`, since it treats everything
219
+ after it as a path filter, not a revision range); the script now rejects any `--range` value
220
+ starting with `-` up front, before any git call runs. Also corrected the fallback's printed
221
+ limitation and code comment: on a MERGE commit, `HEAD~1` is the first parent, so
222
+ `HEAD~1..HEAD` covers the merge PLUS every commit unique to the merged branch (measured on
223
+ this repo's own `4904d76`: 10 commits, not 1) — the prior wording ("only re-covers the last
224
+ commit") was only accurate for a LINEAR multi-commit push, which is now stated explicitly.
225
+ (`src/replay.js`'s phase-less step-window filter was also reviewed and confirmed correct by a
226
+ new adversarial synthetic test — no code change there.)
227
+
10
228
  ## [0.14.0] — 2026-08-25
11
229
 
12
230
  ### Added