bareloop 0.21.0 → 0.23.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 +292 -0
- package/README.md +1 -1
- package/bareloop.context.md +177 -24
- package/package.json +3 -3
- package/src/authorflow.js +7 -2
- package/src/authorjob.js +15 -1
- package/src/authorscout.js +83 -9
- package/src/bundle.js +40 -46
- package/src/calibrate.js +10 -0
- package/src/cli.js +52 -19
- package/src/close-integrity.js +325 -0
- package/src/closetimeout.js +165 -0
- package/src/declaredclose.js +9 -2
- package/src/index.js +14 -0
- package/src/job.js +84 -5
- package/src/judged.js +108 -5
- package/src/kinds.js +12 -0
- package/src/plan.js +5 -1
- package/src/planrun.js +392 -46
- package/src/providers.js +176 -0
- package/src/ralph.js +40 -7
- package/src/ratelimit.js +116 -0
- package/src/reuse.js +12 -2
- package/src/reviewdoor.js +26 -6
- package/src/run.js +83 -8
- package/src/transport.js +29 -12
- package/src/validate.js +59 -0
- package/types/authorscout.d.ts +27 -2
- package/types/close-integrity.d.ts +196 -0
- package/types/closetimeout.d.ts +126 -0
- package/types/declaredclose.d.ts +6 -1
- package/types/index.d.ts +1 -0
- package/types/job.d.ts +4 -0
- package/types/judged.d.ts +7 -2
- package/types/kinds.d.ts +9 -0
- package/types/planrun.d.ts +17 -2
- package/types/providers.d.ts +104 -0
- package/types/ralph.d.ts +19 -5
- package/types/ratelimit.d.ts +59 -0
- package/types/reuse.d.ts +2 -0
- package/types/reviewdoor.d.ts +3 -1
- package/types/run.d.ts +33 -2
- package/types/transport.d.ts +10 -4
- package/types/validate.d.ts +48 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,298 @@ All notable changes to bareloop are documented here. Format:
|
|
|
5
5
|
[SemVer](https://semver.org/spec/v2.0.0.html). Pre-1.0: **minor** = a ladder rung or
|
|
6
6
|
feature lands, **patch** = docs, fixes, scaffolding.
|
|
7
7
|
|
|
8
|
+
## [0.23.0] — 2026-09-09
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **`openai-api` on the provider menu, behind a provider FACTORY** (PRD item 28,
|
|
13
|
+
F149/F150/F156/F157). `src/providers.js` holds one table — provider name →
|
|
14
|
+
constructor, env key, tier models, per-model request-key gating — and both
|
|
15
|
+
runners go through it instead of naming `AnthropicProvider` directly. An
|
|
16
|
+
unknown provider name THROWS; there is no silent default. `openai-api` takes
|
|
17
|
+
an optional validated job-level `baseUrl` (https, or http on loopback only)
|
|
18
|
+
and admits ONE model, `deepseek-chat`, which earned the slot with a real paid
|
|
19
|
+
green through the shipped runner (run `mtu12vks`: green, $1.64 of $4, 10.3 of
|
|
20
|
+
30 min). DeepSeek silently ignores `max_completion_tokens`, so its table entry
|
|
21
|
+
sets bare-agent's `legacyMaxTokens` — an output cap that does not bind is a
|
|
22
|
+
money hazard. The judge stays PINNED to `anthropic-api` and `JUDGE_MODEL`
|
|
23
|
+
whatever the worker's provider is. `bareloop run` (the bundle runner) is
|
|
24
|
+
`ANTHROPIC_API_KEY`-only and REFUSES at $0, naming the key it would have
|
|
25
|
+
needed, rather than building another provider with the wrong key.
|
|
26
|
+
- **`provider` and `baseUrl` on the `job-start` spine record** (F157),
|
|
27
|
+
report-only. Without them an archive cannot separate anthropic rows from
|
|
28
|
+
`openai-api` rows, and every pooled cost or duration figure would be a
|
|
29
|
+
contaminated aggregate.
|
|
30
|
+
- **`stopReason` on every `worker-round`** (BA-13, report-only, null when
|
|
31
|
+
absent, never invented).
|
|
32
|
+
|
|
33
|
+
- **`runner-drained` — a `beforeExit` backstop for the absent-`job-end` class**
|
|
34
|
+
(PRD item 28's ruling (c); F140). A provider promise that never settles
|
|
35
|
+
(BA-25's class) used to let node drain and exit with NO terminal record at
|
|
36
|
+
all — no escalation, no outcome, no way to tell a silent drain from an
|
|
37
|
+
operator kill (F140: 10-of-235 archived spines with no `job-end`, one real
|
|
38
|
+
silent death). bare-agent 0.42 closed the known drop cases (F141), but the
|
|
39
|
+
class itself is "an instrument fires on absence," not a specific bug, so
|
|
40
|
+
the backstop stays needed. `runJob` (`src/run.js`) now registers ONE
|
|
41
|
+
`process.once('beforeExit', …)` right after `job-start`, tracked via a
|
|
42
|
+
local `ended` flag every `job-end` site sets; if the process still drains
|
|
43
|
+
with no `job-end`, it mints one with outcome `runner-drained`,
|
|
44
|
+
`spendComplete:false` (a drained run's in-flight spend is unknowable — the
|
|
45
|
+
floor already banked is honest, F6), and sets `process.exitCode` non-zero
|
|
46
|
+
(never `process.exit()`). The listener is removed in a `finally` so a
|
|
47
|
+
normal run never leaks it. `runner-drained` is a new terminal outcome,
|
|
48
|
+
documented in `bareloop.context.md`'s outcomes list — deliberately **not**
|
|
49
|
+
added to the resumable/checkpoint set (`CHECKPOINT_OUTCOMES`, `src/reuse.js`):
|
|
50
|
+
an unknown in-flight state is not a known-safe resume point.
|
|
51
|
+
|
|
52
|
+
- **Bounded 429 retry — a FALLBACK, not the primary answer** (PRD item 28's
|
|
53
|
+
parked a/b ruling, hamr verbatim: "do a/b as a fallback, and verify/validate
|
|
54
|
+
+ no regression"; F143). A vendor HTTP 429 used to end the whole run as
|
|
55
|
+
`provider-red`, discarding all completed work, even though the vendor's own
|
|
56
|
+
response states exactly how long to wait. `src/ratelimit.js` (new,
|
|
57
|
+
`transport.js`'s sibling) adds ONE bounded retry that honours that stated
|
|
58
|
+
delay, capped at 60s (`RATE_LIMIT_MAX_WAIT_MS`) — a wait longer than that is
|
|
59
|
+
not honoured at all. Wired into `src/planrun.js`'s provider-retry seam
|
|
60
|
+
(`withTransportRetry` renamed `withProviderRetries`) as a SECOND,
|
|
61
|
+
independent one-shot budget alongside the existing F115 transport retry;
|
|
62
|
+
the wall always wins (no retry past the deadline); each retry emits a
|
|
63
|
+
report-only `rate-limit-retry` spine record and does NOT floor
|
|
64
|
+
`spendComplete` (a 429 is a refusal — nothing was billed — unlike a
|
|
65
|
+
transport throw). **The primary answer stays the primary answer**: picking
|
|
66
|
+
a worker model with adequate rate headroom (F139/F143's measured TPM
|
|
67
|
+
table) — this retry only softens the failure mode when that was not
|
|
68
|
+
followed or headroom was still exceeded.
|
|
69
|
+
|
|
70
|
+
### Changed
|
|
71
|
+
|
|
72
|
+
- Bumped `bare-agent` pin from `^0.39.0` to `^0.42.0`. 0.42.0 brings: BA-24 —
|
|
73
|
+
`OpenAIProvider` now sends `max_completion_tokens` by default (GPT-5-safe),
|
|
74
|
+
with a new `legacyMaxTokens` option to send the legacy `max_tokens` key
|
|
75
|
+
instead; BA-25 — a response body cut after headers (peer `'aborted'`,
|
|
76
|
+
stream `'error'`, or a premature `'close'` before `'end'`) now REJECTS
|
|
77
|
+
`generate()` with a retryable `ProviderError` (`context.bound:'transport'`)
|
|
78
|
+
instead of leaving the promise pending forever; a new `loop:truncated`
|
|
79
|
+
stream event plus `stopReason` on the `onLlmResult` metering payload; and
|
|
80
|
+
`options.toolChoice` on `OpenAIProvider`.
|
|
81
|
+
|
|
82
|
+
### Fixed
|
|
83
|
+
|
|
84
|
+
- **F154** — every provider call bareloop makes now carries a deadline. Seven
|
|
85
|
+
sites had none: the softgreen judge, the calibration gate, the authoring
|
|
86
|
+
scout's three rounds, the declaration/revise boundary, and the bridge picker.
|
|
87
|
+
A silent endpoint HANGS the process (an open socket is an active handle, so
|
|
88
|
+
the drain backstop cannot see it); a deadline is the only instrument that
|
|
89
|
+
fires on the absence of events. Tighten-only.
|
|
90
|
+
- **F155** — the judged floor graded whatever LOCATE reported, so a silently
|
|
91
|
+
omitted function passed on the subset. `decide()` now diffs the artifact's own
|
|
92
|
+
top-level functions against the reported set and reds, naming what was
|
|
93
|
+
missing. The declaration shapes live ONCE (`FN_SHAPES`), from which both the
|
|
94
|
+
locate prompt's prose and the detector are derived.
|
|
95
|
+
- **F153** — a provider's own error sentence now reaches the operator instead of
|
|
96
|
+
a bare status number, redacted through the one secret inventory and capped.
|
|
97
|
+
- **F151** — the bounded 429 retry, added last release, fired on a real vendor
|
|
98
|
+
429 for the first time: it parsed the stated wait from prose, waited it, and
|
|
99
|
+
retried once. Mechanism proven; on a TPM-saturated model the retry is not
|
|
100
|
+
expected to recover, and did not.
|
|
101
|
+
- **F147** — the F59 scout summary round (and the authoring scout's recovery
|
|
102
|
+
round, the same shape in `src/authorscout.js`) re-fed a transcript bare-agent
|
|
103
|
+
had already system-prepended into a new `Loop.run()`, which prepended the
|
|
104
|
+
persona AGAIN: two identical system messages at index 0/1. Real OpenAI
|
|
105
|
+
tolerates that; vLLM-class OpenAI-compatible backends reject it (HTTP 400
|
|
106
|
+
"System message must be at the beginning" — the Qwen death F146 left
|
|
107
|
+
unexplained). Both sites now strip the leading system message before
|
|
108
|
+
continuing, as bare-agent's own `Loop.chat()` does. Proven live: the captured
|
|
109
|
+
failing request goes 400 → 200 with one line removed; deepseek-chat then
|
|
110
|
+
greened a full job (F149/F150).
|
|
111
|
+
- **F141** — `src/transport.js`'s `isTransportFailure` now also recognizes
|
|
112
|
+
bare-agent's own BA-25 transport classification
|
|
113
|
+
(`err.context.bound === 'transport'`), after the existing HTTP-status and
|
|
114
|
+
`retryable:false` guards. Before this fix, the exact class hamr's F115
|
|
115
|
+
one-retry ruling names — a call that dies mid-read, no full response —
|
|
116
|
+
would have ended provider-red with no retry once the 0.42.0 pin landed,
|
|
117
|
+
because the new rejection shape carried none of the signals the classifier
|
|
118
|
+
previously looked for (no `status`, `retryable:true`, no matching error
|
|
119
|
+
code/message). Retry budget unchanged: `TRANSPORT_RETRIES = 1`.
|
|
120
|
+
- **Review door refuses `close-timing-red` instead of defaulting the close timeout**
|
|
121
|
+
(F137, `docs/product/CLOSE-INTEGRITY-BUILD.md` "Ruled 2026-09-07", found by
|
|
122
|
+
orchestrator review of M3, run `mtqwmb9l`). `scripts/run-u.mjs`'s `accept` door path
|
|
123
|
+
resolved the mechanical re-run's close timeout via `resolveCloseTimeoutMs` and, when
|
|
124
|
+
that timing pass itself timed out, silently fell through to `closeTimeoutMs:
|
|
125
|
+
undefined` — the library's 120s default — substituting an unauthorized ceiling for a
|
|
126
|
+
door decision, the exact second silent-default class M3 was built to remove one door
|
|
127
|
+
up. A door whose own timing pass times out now REFUSES outright as a named
|
|
128
|
+
`close-timing-red` door stop (same wording/options as the in-run escalation, new pure
|
|
129
|
+
renderer `doorTimingRedLines` in `scripts/u-readout.mjs`): `answerReviewDoor` is never
|
|
130
|
+
called, nothing is recorded (no door record), nothing is released, nothing is spent,
|
|
131
|
+
and the process exits non-zero.
|
|
132
|
+
|
|
133
|
+
## [0.22.0] — 2026-09-07
|
|
134
|
+
|
|
135
|
+
### Added
|
|
136
|
+
|
|
137
|
+
- **Close integrity M1** (`docs/product/CLOSE-INTEGRITY-BUILD.md`, PRD item 27, F129/F131).
|
|
138
|
+
- `src/close-integrity.js`: the ONE `close-absolute-path` detector, shared by
|
|
139
|
+
`src/bundle.js` (export time) and a new $0 run-start precheck in `runPlan`
|
|
140
|
+
(`src/planrun.js`) — every job, not only exported bundles, now refuses at $0
|
|
141
|
+
(before the close-first precheck, before any provider call) when a close
|
|
142
|
+
script's CONTENT bakes in an absolute path that exists on disk. Exports
|
|
143
|
+
`readCloseScripts`, `checkCloseAbsolutePaths`, `absolutePathLiteralsOf` from
|
|
144
|
+
`src/index.js` — `readCloseScripts` is the pure reader M2's sha256 fingerprint
|
|
145
|
+
will reuse.
|
|
146
|
+
- `runJob`/`runPlan` gain an optional `resumable` flag (default `true`,
|
|
147
|
+
`run-u.mjs` unchanged); the bundle CLI (`src/cli.js`) passes `resumable: false`
|
|
148
|
+
so its escalation tail says "resume is `run-u`-only in v1" instead of naming a
|
|
149
|
+
`--resume` flag it does not implement (F130).
|
|
150
|
+
|
|
151
|
+
- **Hermetic test runner** (F136, closed at the runner). `scripts/hermetic.mjs`
|
|
152
|
+
runs `node --test` with `HOME` redirected to a fresh empty `mkdtemp` dir and
|
|
153
|
+
`GIT_CONFIG_GLOBAL`/`GIT_CONFIG_SYSTEM`/`GIT_CONFIG_NOSYSTEM` set to neutralise git
|
|
154
|
+
config, plus any inherited `GIT_AUTHOR_*`/`GIT_COMMITTER_*`/`EMAIL` deleted — the
|
|
155
|
+
local suite is now blind to this machine's identity the same way CI's runner already
|
|
156
|
+
is, so a test leaning on either fails here first. `npm test` now runs it in place of
|
|
157
|
+
a bare `node --test`; not a sandbox (PATH, `node_modules`, shelled-out binaries
|
|
158
|
+
untouched). See `docs/logs/FINDINGS.md` F136.
|
|
159
|
+
|
|
160
|
+
### Fixed
|
|
161
|
+
|
|
162
|
+
- **F129, remaining 8 close scripts**: `scripts/testgen-cold-check-close.mjs`,
|
|
163
|
+
`testgen-close.mjs`, `types-close.mjs`, `l2poc-check-close.mjs`,
|
|
164
|
+
`u-bareagent-close.mjs`, `u-bareguard-close.mjs`, `u-litectx-close.mjs`,
|
|
165
|
+
`u-baremobile-close.mjs` now read `WORKDIR = process.cwd()` instead of a
|
|
166
|
+
hardcoded absolute patient path, following `u-spawner-close.mjs`'s fix
|
|
167
|
+
(`3b987d4`). Behaviour-preserving: `run-u` always passes `cwd` = the patient.
|
|
168
|
+
|
|
169
|
+
- **Close integrity M2 — close-bytes signature** (`docs/product/CLOSE-INTEGRITY-BUILD.md`,
|
|
170
|
+
PRD item 27, N4). A job's signature now covers its close scripts' CONTENT, not only
|
|
171
|
+
the path naming them.
|
|
172
|
+
- New signed spec field `close[].sha256`: hex sha256 of the script file's bytes, for
|
|
173
|
+
every stage whose `cmd` names an addressable script (an interpreter cmd —
|
|
174
|
+
`node`/`sh`/`bash`/`python`/`python3`/`npx` — or a bare directly-executable absolute
|
|
175
|
+
path, e.g. a `.sh` wrapper). It sits inside the signed spec, so `jobSpecHash` covers
|
|
176
|
+
it with no hash-function change. `validateJob` (`src/job.js`) demands it
|
|
177
|
+
(`missing-required`) on every addressable stage and shape-checks it
|
|
178
|
+
(`invalid-value`, 64 lowercase hex chars).
|
|
179
|
+
- `src/close-integrity.js` gains `hashCloseScriptBytes`, `checkCloseByteSignature`,
|
|
180
|
+
`checkStageByteSignature`, `signCloseScripts` (all exported from `src/index.js`).
|
|
181
|
+
`runPlan` verifies the signature at run start (alongside `close-absolute-path`, $0,
|
|
182
|
+
before the close-first precheck and before any provider call) AND before EVERY
|
|
183
|
+
close run thereafter (the `runCloseStages` seam the precheck/preflight/check-passes/
|
|
184
|
+
close-fix-loop all share) — a mismatch reds the new typed fault `close-tampered`
|
|
185
|
+
(`src/ralph.js`'s `CLOSE_FAULTS`), distinct from `close-red`/`close-crashed`.
|
|
186
|
+
- `src/bundle.js`'s `exportBundle` reds `close-sha-mismatch` when a spec's signed
|
|
187
|
+
sha256 disagrees with the script bytes actually being packed — the manifest hash
|
|
188
|
+
and the spec's own signature must never drift apart.
|
|
189
|
+
- `scripts/sign-close.mjs`: a thin CLI wrapper around `signCloseScripts` that fills
|
|
190
|
+
`close[].sha256` from disk and prints the old→new `jobSpecHash`; never writes
|
|
191
|
+
unless `--write`. The agent never writes this field — `src/authorjob.js`'s
|
|
192
|
+
`assembleSpec` refuses a draft carrying `sha256` the same way it refuses
|
|
193
|
+
`close`/`closeDecl`/`verdictType`.
|
|
194
|
+
- **Widened scope (orchestrator audit, folded into this build):** the addressable-script
|
|
195
|
+
shape test (`closeScriptCandidateToken`, `src/validate.js`) now also recognizes a
|
|
196
|
+
bare directly-executable absolute-path cmd (no interpreter prefix) — previously
|
|
197
|
+
invisible to BOTH `close-absolute-path` and this fingerprint. Every `jobs/*.json`
|
|
198
|
+
whose close names a script was re-signed with `scripts/sign-close.mjs --all --write`.
|
|
199
|
+
|
|
200
|
+
- **Close integrity M3 — close timeout: autoset + signed override** (PRD item 27,
|
|
201
|
+
hamr 2026-09-06: "both … autoset and can be override, same like api pricing"; arbiter
|
|
202
|
+
constants set 2026-09-07: floor 120,000ms, K = 5).
|
|
203
|
+
- New `src/closetimeout.js`: `CLOSE_TIMEOUT_FLOOR_MS`, `CLOSE_TIMEOUT_K`,
|
|
204
|
+
`TIMING_PREFLIGHT_CEILING_MS`, `timeCloseStages`, `computeCloseTimeoutCeiling`,
|
|
205
|
+
`resolveCloseTimeoutMs`, `closeTimeoutBanner` (all exported from `src/index.js`). A
|
|
206
|
+
$0 timing preflight runs every close stage once, ignoring verdicts, before the
|
|
207
|
+
close-first precheck and before any provider call; the per-stage ceiling every close
|
|
208
|
+
call in the run then uses is `max(FLOOR, K × slowest measured stage)`, printed on
|
|
209
|
+
every run (`close timeout: <n>s per stage (estimated from seed timing: …)`).
|
|
210
|
+
- New OPTIONAL signed spec field `closeTimeoutMs` (`>= CLOSE_TIMEOUT_FLOOR_MS`,
|
|
211
|
+
`src/job.js`): the operator's own override, which wins outright over the estimate and
|
|
212
|
+
may legally sit above OR below it (the rates-passthrough shape, F113 — not
|
|
213
|
+
tighten-only). Skipped when set: the timing pass never runs. Arbiter territory —
|
|
214
|
+
`src/authorjob.js`'s `assembleSpec` refuses a draft carrying it.
|
|
215
|
+
- New `runPlan` run-start check `wall-under-close-timeout`: refuses at $0 when
|
|
216
|
+
`job.maxWallMs` is under the just-resolved EFFECTIVE close timeout — the honest shape
|
|
217
|
+
once the real (autoset or signed) ceiling is known, never a silent clamp.
|
|
218
|
+
- `scripts/run-u.mjs`'s hardcoded `CLOSE_TIMEOUT_MS = 900_000` retires; the per-stage
|
|
219
|
+
ceiling is resolved once (via the same `resolveCloseTimeoutMs`) before the outside
|
|
220
|
+
watchdog (F67) is even spawned, so its stale/grace windows size off the real number.
|
|
221
|
+
`src/cli.js`'s bundle runner passes nothing — both runners now go through the
|
|
222
|
+
identical autoset/override path.
|
|
223
|
+
- **Part B — `BARELOOP_CLOSE_DIR`.** `runClose` (`src/ralph.js`) accepts an optional
|
|
224
|
+
`closeDir` and sets it as `BARELOOP_CLOSE_DIR` in the close's (already-stripped) env —
|
|
225
|
+
a `BARELOOP_` name matches none of `CLOSE_ENV_DENY`'s rules. New
|
|
226
|
+
`checkCloseDirRequired`/`CLOSE_DIR_ENV_VAR` (`src/close-integrity.js`): a close script
|
|
227
|
+
whose source mentions the variable and gets no `closeDir` refuses at $0
|
|
228
|
+
(`close-dir-required`), the same seam as `close-absolute-path`/`close-tampered`. The
|
|
229
|
+
four hand-authored scripts that hardcoded an external `SPINE_DIR`
|
|
230
|
+
(`testgen-cold-check-close.mjs`, `testgen-close.mjs`, `l2poc-check-close.mjs`,
|
|
231
|
+
`types-close.mjs`) now read `process.env.BARELOOP_CLOSE_DIR` and instrument-stop
|
|
232
|
+
(exit 97) when it is absent — no baked fallback. `scripts/u-pulselog-close.mjs`'s
|
|
233
|
+
hardcoded `--workdir` DEFAULT (a separate F129 cwd-class hazard — that literal existed
|
|
234
|
+
on disk and already tripped the shipped `close-absolute-path` guard for
|
|
235
|
+
`jobs/pulselog-u-types.json`) now falls back to `process.cwd()`, the same M1 template
|
|
236
|
+
every other close script uses. `src/cli.js` sets `closeDir` to
|
|
237
|
+
`<bundleDir>/runs/<runid>/close/`; `scripts/run-u.mjs` sets it to its existing
|
|
238
|
+
`spineDir`. Every `jobs/*.json` whose close bytes changed was re-signed
|
|
239
|
+
(`scripts/sign-close.mjs --all --write`).
|
|
240
|
+
|
|
241
|
+
- **F132 — a real paid fire of an exported bundle refused itself `close-tampered`
|
|
242
|
+
at $0** (run `mtqwmb9l` → export → `mtqwydl4`). `exportBundle`'s import rewrite
|
|
243
|
+
(`../src/x.js` → `'bareloop'`) changes a close script's bytes, but the written
|
|
244
|
+
bundle's `spec.json` kept the SOURCE spec's `close[].sha256` unchanged — two
|
|
245
|
+
signatures over two different byte strings, so the run-start
|
|
246
|
+
`checkCloseByteSignature` correctly refused a bundle that was never actually
|
|
247
|
+
tampered with. `exportBundle` (`src/bundle.js`) now re-signs `close[].sha256`
|
|
248
|
+
in the written spec over the RELOCATED bytes it actually packs, for every
|
|
249
|
+
stage that already carries a signature — the export-time `close-sha-mismatch`
|
|
250
|
+
check against the SOURCE spec/bytes is unchanged (it still guards a tampered
|
|
251
|
+
source).
|
|
252
|
+
|
|
253
|
+
- **F133 — double/mislabelled close-timeout banner** (run `mtqwmb9l`). `runPlan`
|
|
254
|
+
printed/emitted "estimated from seed timing" (`scripts/run-u.mjs`'s own
|
|
255
|
+
resolution, needed early to size the outside watchdog, F67) AND, on the same
|
|
256
|
+
run, "explicit runner override" (the library's own print, because run-u also
|
|
257
|
+
fed the resolved number back in as a bare `closeTimeoutMs`) — two lines for
|
|
258
|
+
one number, the second lying about its source. `scripts/run-u.mjs` no longer
|
|
259
|
+
passes `closeTimeoutMs` into `runJob` at all; `runJob`/`runPlan` resolve
|
|
260
|
+
(autoset, or the spec's own signed field) and announce the ceiling themselves
|
|
261
|
+
— the ONE banner/spine record per run. The runtime `closeTimeoutMs` option on
|
|
262
|
+
`runJob`/`runPlan` stays, test/backward-compat only. Same fire, second (real)
|
|
263
|
+
catch: run-u's own pre-fix early `emit('close-timing', …)` landed BEFORE
|
|
264
|
+
`job-start` on the spine (`runJob` is what emits `job-start`, and run-u called
|
|
265
|
+
it before ever calling `runJob`) — every spine reader assumes `job-start`
|
|
266
|
+
opens the file. Fixed by the same change (run-u no longer emits it early);
|
|
267
|
+
`tests/readshim-battery.test.js`'s archive check now tolerates `job-start`
|
|
268
|
+
within the first 3 records (the archived `u-mtqwmb9l.jsonl` is real and never
|
|
269
|
+
rewritten), and a new test pins `job-start` as literally the first record on
|
|
270
|
+
a fresh scripted run.
|
|
271
|
+
|
|
272
|
+
- **F135 — review-door accept re-run bypassed the close byte signature**. Every
|
|
273
|
+
other close execution goes through `checkStageByteSignature` before running
|
|
274
|
+
a stage (`runCloseStages`, `src/planrun.js`); the review door's `accept`
|
|
275
|
+
re-proof (`proveMechanically`, `src/reviewdoor.js`) called
|
|
276
|
+
`runStages`/`runDeclaredStages` directly and skipped it — a close script
|
|
277
|
+
swapped on disk after the run ended but before the signer's accept ran
|
|
278
|
+
unchecked and could mint a false accept. Fixed: `proveMechanically` now
|
|
279
|
+
verifies the mechanical stages' bytes against their signed `sha256` first,
|
|
280
|
+
refusing through the existing `door-accept-red` path on a mismatch
|
|
281
|
+
(`tests/reviewdoor-tamper.test.js`).
|
|
282
|
+
|
|
283
|
+
- **F134 — live re-fire validation, no code change**. Two real paid fires of the
|
|
284
|
+
same exported bundle (`mtr0icky` cap-halt, `mtr4t1u1` green re-fire) confirmed
|
|
285
|
+
M2's relocated-bytes signature and M3's close-timing banner both hold under a
|
|
286
|
+
second real fire, not just the one that motivated each fix; the cap-halt
|
|
287
|
+
itself read as a cap-shaped negative (an `Any`-suppression cheat correctly
|
|
288
|
+
caught by `no-suppressions`, not an instrument defect). See
|
|
289
|
+
`docs/logs/FINDINGS.md` F134.
|
|
290
|
+
|
|
291
|
+
- **F136 — CI-only red: patient test fixtures committed without the neutralised
|
|
292
|
+
git identity**. `tests/close-integrity.test.js` and `tests/close-timeout.test.js`
|
|
293
|
+
each added a second commit on top of `initPatientRepo`'s seed via a raw
|
|
294
|
+
`execFileSync('git', ...)` with no env, so it depended on the host's own git
|
|
295
|
+
identity — green on hamr's machine (a global config papers over it), red on
|
|
296
|
+
CI (none). `tests/helpers.js` now exports `patientGitEnv`/`gitInPatient`
|
|
297
|
+
reusing `initPatientRepo`'s identity env; both files' `makePatient` go through
|
|
298
|
+
it. See `docs/logs/FINDINGS.md` F136.
|
|
299
|
+
|
|
8
300
|
## [0.21.0] — 2026-09-06
|
|
9
301
|
|
|
10
302
|
### Added
|
package/README.md
CHANGED
|
@@ -82,7 +82,7 @@ A signed job spec goes in. A verdict comes out.
|
|
|
82
82
|
|
|
83
83
|
```js
|
|
84
84
|
import { runJob, jobSpecHash, makeSpine } from 'bareloop';
|
|
85
|
-
import { AnthropicProvider } from 'bare-agent';
|
|
85
|
+
import { AnthropicProvider } from 'bare-agent/providers';
|
|
86
86
|
|
|
87
87
|
const spec = {
|
|
88
88
|
schema: 'job-v1',
|