bareloop 0.25.0 → 0.26.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
@@ -5,6 +5,323 @@ 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.26.0] — 2026-09-14
9
+
10
+ ### Added
11
+
12
+ - **Source and Destination replace `--patient` (PRD item 33 M3, ruling 2):**
13
+ `scripts/run-interview.mjs` now asks Source and Destination as its own first two interactive
14
+ questions, before the picked verdict class's frozen set — never a `--patient` flag. Each is
15
+ proven mechanically, $0, the moment it is answered: Source is checked against the machine and
16
+ (for a local directory) language-detected immediately; Destination's SHAPE depends on what
17
+ Source turned out to be (the same `looksLikeRepoSource` rule `prepareSource` itself uses to
18
+ route this, now exported from `src/source.js` rather than duplicated) — for a repo Source, the
19
+ answer IS the write fence and fills `draft.writeScope` directly (the separate "FENCE" question
20
+ is gone); for every other kind, it is re-asked in a loop until it names an absolute, writable
21
+ directory (`proveDestination`). The moment both are answered, the interview calls
22
+ `prepareSource` itself to freeze Source into a hidden scratch copy under a fresh `into` nested
23
+ inside `--out`, and everything downstream — the class's own questions, the job spec's
24
+ `description`, and the `--source` handed to `scripts/run-author.mjs` — reads that PREPARED
25
+ COPY, never the original again. A non-repo Source gets Source and Destination proven and
26
+ frozen and then an honest named stop: bareloop's check catalogue is code-genre only today
27
+ (ruling 7 → M4); the prepared copy stays on disk regardless. `scripts/run-author.mjs` gains
28
+ `--source <tree>`, replacing `--patient <repoPath>`: it must be a tree a source door already
29
+ prepared (`readSourceManifest(dirname(source))` finds a manifest of kind `'repo'` beside it) —
30
+ an unprepared path dies loud naming the exact `scripts/prep-source.mjs` command to run first,
31
+ and a prepared non-repo source gets the same honest M4 stop, now recorded to the spine as
32
+ counted demand. `scripts/prep-source.mjs`'s printed next-step command follows suit.
33
+
34
+ - **A Source inside a repo (e.g. a monorepo package) is now a repo job (hamr's ruling A, PRD
35
+ item 34 loose end):** `looksLikeRepoSource`/`prepareSource` (`src/source.js`) used to treat a
36
+ folder as a repo source only when `.git` sat directly inside it, so a Source like
37
+ `myrepo/packages/api` fell to the plain-folder path (no checks yet, M4) and could hit an
38
+ untracked `node_modules` symlink as a refusal. A new `nearestGitAncestor(startDir)` walks up
39
+ from a directory to the nearest ancestor carrying a `.git` entry (a real repo directory, or a
40
+ linked-worktree/submodule file) — the one walk now shared by `looksLikeRepoSource`,
41
+ `prepareSource`'s own routing, and `src/detectlang.js`'s boundary walk, replacing three
42
+ separate copies. `prepareSource`'s directory branch freezes the WHOLE found repo's tracked
43
+ files when Source is a subfolder, exactly as it already did for a repo-root Source; the
44
+ manifest gains a `sourceSubdir` field (Source's path relative to the repo root, `''` at the
45
+ root) for a later piece to wire into scope — nothing reads it yet. Edge case, reported not
46
+ solved: a Source pointed at a deep folder under a large repo (e.g. one's whole home directory)
47
+ now freezes that WHOLE repo's tracked files, with no size or depth limit to catch it.
48
+
49
+ - **Language auto-detection (PRD item 33 M3, ruling 3):** `src/detectlang.js`'s `detectLanguage`
50
+ reads a code job's language off its own repository — `package.json` → js (TypeScript
51
+ included), `pyproject.toml`/`setup.py` → python — walking up from the Source folder to the
52
+ nearest ancestor manifest, never past the repository root (the nearest `.git`). A known
53
+ manifest this catalogue has no genre data for yet (`go.mod`, `Cargo.toml`, `pom.xml`,
54
+ `build.gradle(.kts)`, `*.csproj`/`*.sln`, `composer.json`) is a named `language-unsupported`
55
+ stop — never a silent fallback to js — carrying a `Refusal` shaped exactly like
56
+ `src/authorjob.js`'s own (`REFUSAL_LIB`/`REFUSAL_CATEGORY`, `request-red`). Two manifests at
57
+ the same nearest level is a named `ambiguous` result listing both; no manifest anywhere is
58
+ `no-code-job`, which is NOT an error (a plain-folder job still gets the form; M4 gives it
59
+ checks). The whole known-language table is one data list, keyed against `GENRE_LANGUAGES`
60
+ (`src/authoring.js`) — a later language landing there (M3b) needs no new code path here.
61
+
62
+ - **The question sets become the unified intake form (PRD item 33 M3 piece 3, signed ruling
63
+ "The intake form (RULED)").** `src/authorflow.js` reshapes the green/soft-green/hitl question
64
+ sets to the ruled 6-field form: Source and Destination (already asked as mechanical fields
65
+ since M3 piece 2) plus a free-text trio, numbered contiguously 1-3, whose text is now the
66
+ signed table's own "Holds" column, VERBATIM: Goal ("what you want to achieve"), What success
67
+ looks like ("checks a machine can count"), and Guardrails ("what must not happen or change" —
68
+ the old "must not change" and "worse than before" questions JOINED into one field; "worse than
69
+ before" is gone from the form entirely, moving to the confirm turn, piece 4, repo-only — now
70
+ built, see below). Soft-green adds a fourth field, Judge Examples ("one pass, one fail, and why" — the
71
+ old Q6 is retired as its own question, since the "why" half of a real pass/fail pair is what
72
+ `cardauthor.js`'s rubric compile already read it for). Each field's LABEL (Goal / What success
73
+ looks like / Guardrails / Judge examples) is shown for the first time too — a new `labelsFor`
74
+ reader alongside `questionsFor`/`requiredAnswersFor`, and the composer's own interview block
75
+ now shows the label with each answer. hitl (never shown, kept in code) renumbers the same way,
76
+ with no signed-table label for its own fourth question. Source and Destination's own wording
77
+ now also lives in `src/authorflow.js` (`SOURCE_FIELD`, `DESTINATION_FIELD_REPO`,
78
+ `DESTINATION_FIELD_PLAIN`, `destinationFieldFor`), so `scripts/run-interview.mjs` prints
79
+ library text for all six fields, none of its own. What the old Q2 used to tell the composer
80
+ (which files change, which are read-only) now reaches `authorPrompt` through a new optional
81
+ `writeScope` parameter (`writeScopeBlock`), fed from Destination's own proven write-scope
82
+ fence end to end (`authorClose` → `authorCloseForJob` → `scripts/run-author.mjs`'s
83
+ `draft.writeScope`) rather than silently vanishing.
84
+
85
+ - **The confirm turn (PRD item 33 M3 piece 4).** After the survey, `scripts/run-author.mjs`
86
+ now runs a paid, interactive confirm turn (`runConfirmTurn`, `src/authorjob.js` →
87
+ `src/authorflow.js`) before authoring: a $0 half (repo-only "worse than before", an
88
+ ambiguous-language pick, both asked BEFORE the scout) followed by up to 2 paid rounds where
89
+ the model drafts a plan — every check it will compose, the always-on guards as PROTECTIONS
90
+ (never named in the goal), and one signed goal sentence — and the person confirms it, fixes
91
+ it, types the goal themselves, or starts over. No hand-authored matcher ever compares the
92
+ goal against the checks (ruling 6) — the model states its own plan and the person is the one
93
+ judgement that accepts it. `scripts/run-interview.mjs` asks no separate goal question any
94
+ more (ruling 5's addendum, D2 = option B) and no longer dies on an ambiguous-language Source
95
+ (it defers the pick to the confirm turn, D7); `run-author.mjs`'s own ambiguous-language die()
96
+ is likewise gone. The confirm turn's own cost book absorbs the scout's prior spend (and its
97
+ own `costUsd: null` calls) before its first `capStop()` check, so a scout that already spent
98
+ most of the ceiling is visible to it immediately — only the confirm turn's OWN new calls
99
+ travel onward to `authorClose` as `priorCalls`/`priorRaws`, never the scout's a second time.
100
+ `run-author.mjs` is now interactive: a readline `ask` seam (same idiom as
101
+ `run-interview.mjs`'s own), closed in a `finally` around the whole paid span. The confirm
102
+ turn's open questions (a round-2 "fix" passed to the composer verbatim) print at the SIGNING
103
+ PREPARED readout (`openQuestionLines`, `scripts/author-readout.mjs`) — the signed spec format
104
+ itself is unchanged. `authorClose` gains a `confirmed` plan fed into `authorPrompt`'s new
105
+ `confirmedBlock` ("compose these checks and no other"). Every existing caller of
106
+ `authorCloseForJob`/`authorClose`/`authorPrompt` that passes no `ask` runs byte-identical to
107
+ before this piece existed. **`TYPES_GENRE_TEMPLATE` now composes its WORK stages only for a
108
+ confirmed check (D6 = A, "replace it", item 33 step S7):** the frozen TYPES genre template's
109
+ old unconditional work-stage skeleton (`typecheck`, `typecheck-outside`, `tests-kept`,
110
+ `suite-green`) and unconditional STRICT-checker mandate conflicted with ruling 6 ("a genre
111
+ never adds a check the goal did not ask for") for exactly the case run mtv8jihy surfaced (an
112
+ unasked `tsc --strict` stage). The STRICT form of the checker, and the WORK stages themselves,
113
+ are now composed only when a confirmed check — or, absent a confirm turn, the goal and
114
+ interview answers — asks for them; the GUARDS (`changed-from-seed`, `no-suppressions`) stay
115
+ always on, unaffected, since they are enforced structurally (`classGuards` +
116
+ `validateDeclaration`'s guards-absent red), never by this prompt text. The template is prompt
117
+ text handed to the authoring model only — never hashed into a signed spec, `closeDecl`, bundle
118
+ manifest, or bench row signature — so this edit changes nothing about an already-signed close.
119
+ `tests/authoring.test.js`'s byte-identity test is re-pinned to the new frozen block.
120
+ `scripts/run-interview.mjs` asks no separate GOAL question any more (ruling 5's
121
+ addendum, D2 = option B) and no longer dies on an ambiguous-language Source (D7 defers the
122
+ pick to the confirm turn); its own $0 validator pass filters both `goal`
123
+ (`CONFIRM_AUTHORED_FIELDS`) and, for a plain-folder job, `writeScope`
124
+ (`PLAIN_FOLDER_DEFERRED_FIELDS`, both `src/authorjob.js`) reds the same way it already filters
125
+ `AUTHORED_SPEC_FIELDS`'s. **A plain-folder Source no longer stops the interview at all (PRD
126
+ item 33 M3 piece 4, step S6, D5 = A ruling):** the form continues — class questions, job name,
127
+ budget, wall, and the offer — and the draft is written with no `writeScope` (Destination there
128
+ is an output directory, never a fence). The honest "no checks yet" stop (ruling 7 → M4) moves
129
+ to `run-author.mjs`, which now runs a plain-folder job's confirm turn too — over a $0, no-git
130
+ listing of the frozen tree rather than a scout (D5: the scout's register is code-only) — before
131
+ giving that same stop. If the confirm turn itself does not reach a signed plan, that stop
132
+ stands instead; the non-code-source stop only fires once a person actually confirmed one.
133
+
134
+ ### Removed
135
+
136
+ - **BREAKING: soft-green's rubric-card/calibration answer keys change shape (PRD item 33 M3
137
+ piece 3).** The old two-question pair (`answers[6]`, `answers[7]`) is now ONE answer at key
138
+ `4` (`SOFTGREEN_JUDGE_EXAMPLES_KEY`) — `src/cardauthor.js`'s `cardCasesPrompt` reads that one
139
+ key instead. Any hand-authored `answers.json` from before this change needs its keys
140
+ reshaped: green's old five (1-5) become three (1-3, Guardrails absorbing the old 3 and 5);
141
+ soft-green's old seven (1-7) become four (1-4).
142
+ - **BREAKING: `--patient` is gone from `scripts/run-interview.mjs` and `scripts/run-author.mjs`
143
+ (PRD item 33 M3, ruling 2).** `run-interview.mjs` asks Source (and Destination) as its own
144
+ first questions instead; `run-author.mjs` takes `--source <tree>`, which must be a prepared
145
+ copy (see "Added", above). Passing `--patient` to either script now is a loud, explicit
146
+ refusal naming its replacement, rather than a silently-ignored or misrouted flag.
147
+ - **BREAKING: `--lang` is gone from `scripts/run-interview.mjs` and `scripts/run-author.mjs`.**
148
+ Language is now auto-detected from Source's own repository (see "Added", above) — it is
149
+ a fact of the repo, never a flag a person sets. Passing `--lang` now is a loud, explicit
150
+ refusal naming the flag and why, rather than a silently-ignored no-op.
151
+
152
+ ### Fixed
153
+
154
+ - **The confirm turn's "protections" now come from code, never the model (item 34 loose-end
155
+ fix, finding #1 from live run mu0voeo4):** the confirm turn used to display whatever prose the
156
+ model invented for `protections`, and one live run invented a "behavior-preservation guard"
157
+ this build has no way to check (no kind in the catalogue can verify runtime behaviour). The
158
+ model is no longer asked for `protections` at all — the schema dropped the field — and what a
159
+ person sees and what gets recorded as `accepted.protections` is now rendered from the SAME
160
+ guards `classGuards` will actually compose (`src/authoring.js`'s `MECHANICAL_GUARDS`), through
161
+ a frozen plain-English line per guard (`GUARD_DESCRIPTIONS`, `src/authorflow.js`), plus the
162
+ write fence when one is set. The model instead returns `notChecked` — anything the person asked
163
+ for that no listed check can verify — shown under its own heading in the menu and in the
164
+ composer's confirmed-plan block, never silently dropped.
165
+ - **`run-interview.mjs`'s paid-step hand-off no longer describes a scout a plain folder
166
+ never gets (item 34 loose-end fix):** since 21561cf (D5=A), a non-repo Source gets no
167
+ scout — the confirm turn reads the file list and `run-author.mjs` stops at the M4 wall
168
+ ("no checks for this kind of job yet") before signing is ever reached. The hand-off text
169
+ printed the repo-only wording ("a real scout over that repository", "It stops at
170
+ prepareSigning") for every source regardless. A plain-folder session now prints its own
171
+ line naming the confirm turn and the M4 stop; a repo session's wording is unchanged.
172
+ - **`run-author.mjs`'s `language-unsupported` stop is now counted admission demand (item 34
173
+ loose-end fix on M3):** the check used to print the refusal and `process.exit(1)` before the
174
+ run's spine even existed, so nothing recorded it. The spine is now bootstrapped first (before
175
+ any provider is resolved, before the API key is read, before any spend) and the stop is
176
+ emitted through the same `refusalEvents()` channel every other refusal in the script uses,
177
+ so it folds into `src/ledger.js`'s `classifyIncidents` admission count instead of vanishing.
178
+ `run-interview.mjs`'s own printed line for the same stop no longer claims "the refusal IS the
179
+ record" — that script keeps no spine of its own, so it now says plainly that nothing here
180
+ recorded it, and points at `run-author.mjs` for the one that does.
181
+ - **Scan-then-freeze TOCTOU closed in the source front door (PRD item 34 L1):**
182
+ `prepareSource`'s folder/repo path used to hash+secret-scan each file's bytes once, then
183
+ re-read the same file a SECOND time off disk (`copyFile`) to freeze it into the hidden
184
+ tree — a window where a file changed on disk between the two reads would have its secret
185
+ scan run against different bytes than the ones actually frozen. The freeze step now
186
+ re-hashes its own (second) read and refuses (`source-changed-after-scan`) on any mismatch
187
+ against the scan-time hash, rather than caching every file's buffer (which would hold a
188
+ whole repo in memory at once — the streaming scan design exists to avoid exactly that).
189
+ `copyFile`'s mode-bit preservation is kept explicitly (`stat` + `chmod` on the frozen
190
+ file), verified not to regress.
191
+ - **A gitignored/untracked subfolder inside a repo no longer freezes into an empty
192
+ claim (hamr's ruling A, PRD item 34 loose end, 2026-09-13):** the ruling-2 addendum's
193
+ "a Source subfolder is a repo job" rework froze the WHOLE repo's tracked files, but
194
+ `listRepoFiles` only ever returns tracked paths — when Source itself is a subfolder git
195
+ tracks nothing under (`.gitignore`'d, or simply never committed), the freeze used to
196
+ succeed anyway with a `kind: 'repo'` tree holding none of Source's own files, silently
197
+ vanishing the person's input. `prepareSource` now refuses `source-untracked-in-repo`
198
+ before `into` is created — a repo-root Source, and a subfolder with at least one tracked
199
+ file underneath it, are unaffected.
200
+ - **The documented-exports guard now reads the doc instead of a hand-typed array (F167,
201
+ PRD item 34 L4):** `tests/index.test.js`'s "documented public surface" test used to check
202
+ a list of names copied out of `bareloop.context.md` by hand — the same class of bug that
203
+ let `datedDestination`/`pickDelivery` ship `undefined` in v0.25.0 while the guard stayed
204
+ green. `documentedExportNames` now parses the doc live (import-block examples, Public API
205
+ section headings, `Menus exported:` lists, and tight "X is/are exported" proximity) and
206
+ found two more real gaps the hand list missed: `cliMain` and (already fixed) the two
207
+ source-front-door helpers. Covers the doc's explicit export-marker idioms, not every
208
+ function mentioned in flowing prose — a broader sweep was tried and produced 21 false
209
+ positives out of 97 candidates on this doc, noise a regex cannot safely resolve.
210
+ - **The export list now equals the documented contract exactly, guarded both ways (PRD
211
+ item 34 L20):** the 91 undocumented names that were genuinely discussed in
212
+ `bareloop.context.md` prose (the "Close authoring", "Bundles", "THE REVIEW DOOR", "The
213
+ reuse ENVELOPE" and ledger sections — none of which used per-function `###` headings, so
214
+ the extractor's marker idioms could not credit any name in them) now carry an explicit
215
+ `import { ... } from 'bareloop'` marker next to their existing prose, including
216
+ `JUDGED_MARKER` (previously undocumented anywhere despite being required by every close
217
+ script this repo ships and by `exportBundle`'s `close-import-unexported` legality check).
218
+ `tests/index.test.js`'s guard is now a full two-way check — every export must be
219
+ documented and every documented name must be exported — replacing the one-directional
220
+ guard and the item-34-L4-scoped "37 restored" test, both now fully subsumed. Two
221
+ exclusions carry forward unchanged: `main` (the doc's pre-rename local name for the real
222
+ export `cliMain`) and `resumableOutcomes` (its own "exported" sentence describes "bundle",
223
+ not this name — the real export is `CHECKPOINT_OUTCOMES`).
224
+ - **The doc-reading extractor's own coverage gap closed (PRD item 34 L4 follow-up):** the
225
+ switch to reading `bareloop.context.md` live covered fewer names than the hand-typed array
226
+ it replaced — 37 exported names (`mintBridge`, `appendGreen`, `BRIDGE_SCHEMA`, the rest of
227
+ the reuse registry, plus `runStages`/`globToPrefix`/`scanSecrets`/three ledger helpers) sat
228
+ in flowing prose with no marker idiom the extractor reads, so the guard silently stopped
229
+ covering them. `bareloop.context.md` now carries an explicit marker (an `import { ... }
230
+ from 'bareloop'` example, or a tight "X is/are exported" sentence) for each of the 37, and
231
+ `tests/index.test.js` pins that they stay derived. A live count found 169 of
232
+ `src/index.js`'s 255 exports still undocumented by any marker idiom — reported, not fixed
233
+ here; a full reverse guard (every real export documented) was considered and rejected as
234
+ out of this fix's scope.
235
+ - **`SCOUT_LABEL` gains a third state in `scripts/run-u.mjs` (PRD item 34 L2):** an explicit
236
+ `--scout on` used to print the identical "scout ON (default)" text as no flag at all,
237
+ indistinguishable in printed logs/re-invocation lines — which matters for the
238
+ SCOUT-CONTRAST bench row's provenance. It now prints `scout ON (--scout on — operator
239
+ explicit)`, distinct from the true default and from `--scout off`'s unchanged label.
240
+ - **Job authoring is LLM-agnostic (PRD item 34 L17):** `scripts/run-author.mjs` no longer
241
+ forces `PROVIDER_NAME = 'anthropic-api'` for its scout and drafter — the identity is now
242
+ resolved from the operator's own draft (`resolveProvider(draft.provider)`), the same
243
+ no-flag/no-default rule `scripts/run-u.mjs` applies to the worker; a missing or
244
+ unrecognized draft provider dies loud, at $0, before any paid call, naming the known
245
+ table. `scripts/run-interview.mjs` gains a REQUIRED `--provider` flag with no default (a
246
+ default would silently re-lock every interview onto one vendor) and writes it into the
247
+ draft; the paid-step offer's key line and unset-key notice now name whichever provider's
248
+ own env var applies, never a hardcoded `ANTHROPIC_API_KEY`. Non-Anthropic drafting is
249
+ legal as of this change but not yet proven live — that is M3's DeepSeek proof run, not
250
+ this one.
251
+
252
+ ### Docs
253
+
254
+ - **`npx @scope/pkg`-shaped close commands documented as a KNOWN, KEPT limit (PRD item 34
255
+ L3):** `closeScriptCandidateToken`'s path-shaped test (`src/validate.js`) reads a scoped
256
+ package name as a script path because it contains `/`, so such a close can never be
257
+ signed — `bareloop.context.md` now says so next to the scope note it belongs beside. Not
258
+ fixed: it fails safe and no shipped job uses the shape.
259
+
260
+ ### Changed
261
+
262
+ - **DeepSeek secondary model swap (F171, PRD item 34 L16):** `deepseek-chat` is no longer
263
+ served by DeepSeek's API (a live `/models` call returned only `deepseek-flash` and
264
+ `deepseek-v4-pro`). The `openai-api` tier table (`src/providers.js`) and its per-model
265
+ `legacyMaxTokens` request-key gating now name `deepseek-flash`. F149's gating measurement
266
+ was taken on `deepseek-chat` and is carried forward UNVERIFIED on `deepseek-flash`;
267
+ pricing stays the estimated default (F113 unchanged).
268
+ - **`hitl` removed from every customer-facing surface (PRD item 34 L19):** `bareloop.context.md`,
269
+ and the usage/help text of `scripts/run-author.mjs` and `scripts/run-interview.mjs`, no
270
+ longer name `hitl` anywhere. The class, its terminals (`hitl-pause`, `hitl-decision-red`,
271
+ the legacy human-close terminal) and its `human-confirms` stage kind are untouched in code —
272
+ kept admitted for reuse, never revived, never shown to a customer again. The counted-demand
273
+ refusal a person sees when they pick an off-menu verdict class is unchanged (it names the
274
+ class and fwdloop by design). `tests/hitl-hidden.test.js` pins the doc and both scripts
275
+ case-insensitively hitl-free.
276
+
277
+ ### Removed
278
+
279
+ - **BREAKING: 78 undocumented names dropped from the `src/index.js` root export list (PRD
280
+ item 34 L20, owner's option A):** a live audit found 169 of 255 root exports had zero real
281
+ citation in `bareloop.context.md`; 91 of those were genuinely discussed in the doc's
282
+ prose and gained an explicit marker (see Fixed, above) instead of being dropped, but the
283
+ remaining 78 had no adopter-facing mention anywhere and no in-repo consumer reaching them
284
+ through the package root — a name imported directly from `import { x } from 'bareloop'`
285
+ and nothing else. Every dropped name's own module is untouched; only the root re-export
286
+ is gone, and each still exists inside its own module for the library's own internal use —
287
+ but `package.json`'s `exports` map only `"."` to `src/index.js`, so a package user can no
288
+ longer reach any of them, including via a submodule path such as `src/text.js`. Dropped:
289
+ `artifactHash`, `authorPrompt`,
290
+ `BASELINES`, `CALIBRATION_LABEL`, `cardCasesPrompt`, `CASE_VERDICTS`, `CATALOGUE_KINDS`,
291
+ `CATALOGUE_LIVE_KINDS`, `changedSet`, `classifySurvey`, `classMenu`, `CLASS_STATEMENTS`,
292
+ `CLOSE_DECL_FIELDS`, `closeGrade`, `compareExpectation`, `COMPILE_SYSTEM`,
293
+ `createReadShim`, `declarationSchema`, `DECLARED_CLOSE_CLASSES`, `DECLARED_GAP_KEEP`,
294
+ `DECLARED_GAP_PREFIX`, `DECLARED_GENRES`, `defaultJudgeLoop`, `DIRECTIONS`, `doorAgeGate`,
295
+ `doorRecordOf`, `EXIT_GREEN`, `EXIT_RED`, `EXIT_STOP`, `factsResist`, `GENRE`,
296
+ `GENRE_LANGUAGES`, `genreOwnedEnvNames`, `GREEN_QUESTIONS`, `guardNames`,
297
+ `HITL_DECISION_RED`, `HITL_PAUSE`, `HUMAN_CHECKPOINTS`, `INJECTION_CARD`,
298
+ `isDeclaredClose`, `JUDGED_FLOOR_KIND`, `JUDGE_MAX_TOKENS`, `LIVE_CLASSES`,
299
+ `LOCATE_AXES`, `LOCATE_LABEL`, `locatePrompt`, `makeLoopGenerate`, `makeSeedTrees`,
300
+ `MAX_PROPOSAL_RETRIES`, `MAX_STAGES`, `normalizeDeclaration`, `prepareWorkBranch`,
301
+ `PROPOSAL_LABEL`, `proposalSchema`, `proposalTool`, `PROPOSAL_TOOL_NAME`,
302
+ `QUARANTINED_CODE`, `QUESTION_SETS`, `RAW_TRIM_MARKER`, `READ_SHIM_ARMS`,
303
+ `readShimStrategy`, `REFUSAL_CATEGORY`, `REFUSAL_LIB`, `REVIEW_DOOR`, `seedFileList`,
304
+ `seedListing`, `shapeForkName`, `SOFTGREEN_QUESTIONS`, `SURVEY_CAUSES`, `TYPES_GENRE`,
305
+ `TYPES_GENRE_TEMPLATE`, `validateCard`, `validateFacts`, `validateJudgedArtifacts`,
306
+ `VERDICT_CLASSES`, `WORK_BRANCH_PREFIX`, `WORK_BRANCH_RE`, `wrapReadTool`. No in-repo
307
+ importer reached any of these through the package root (verified against every
308
+ `from '../src/index.js'` / `from './index.js'` / `from 'bareloop'` site in the tree), so
309
+ nothing else in this repo needed a path change.
310
+
311
+ ## [0.25.1] — 2026-09-13
312
+
313
+ ### Fixed
314
+
315
+ - **Package-root export gap (PRD item 33/M2 follow-up):** `bareloop.context.md` documents
316
+ `datedDestination(destination, now, n)` and `pickDelivery(destination, now?)` as exported
317
+ from the package root, but `src/index.js`'s `./source.js` re-export only carried
318
+ `prepareSource`, `proveDestination`, `copyOut`, `readSourceManifest`,
319
+ `frontDoorFromManifest` — both helpers existed in `src/source.js` but were `undefined`
320
+ when imported as `import { datedDestination, pickDelivery } from 'bareloop'`. Caught by a
321
+ clean-consumer import check of the published v0.25.0 package. Both names are now
322
+ re-exported from `src/index.js`; `tests/index.test.js` pins them against `src/source.js`
323
+ identity.
324
+
8
325
  ## [0.25.0] — 2026-09-12
9
326
 
10
327
  ### Added