bareloop 0.9.0 → 0.11.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.
@@ -102,6 +102,60 @@ export function genreEnv(lang: string, { sourcePrefixes }?: {
102
102
  * one of them, because ownership is only real if it is mechanical.
103
103
  * @param {string} lang @returns {string[]} */
104
104
  export function genreOwnedEnvNames(lang: string): string[];
105
+ /**
106
+ * HOW THE GENRE'S OWN TOOLS PRINT — genre property, like the suppression battery
107
+ * and like `MYPYPATH`, and for the same reason: it is a FACT ABOUT AN INSTRUMENT
108
+ * WE ALREADY OWN, not a composition choice. Seven hand-written closes read tsc
109
+ * with the identical `/error TS\d+/` (`scripts/u-pulselog-close.mjs:122`,
110
+ * `u-bareguard-close.mjs:123`, `u-bareagent-close.mjs:123`,
111
+ * `u-baremobile-close.mjs:122`, `u-litectx-close.mjs:140`, `types-close.mjs:190`,
112
+ * `types-check.mjs:60`) and one reads mypy with `' error: '`
113
+ * (`u-spawner-close.mjs:133`) — the same provenance the SUPPRESSIONS table has:
114
+ * operator knowledge minted by paying for live runs.
115
+ *
116
+ * WHY IT BECAME GENRE DATA (run msmbpjk6, 2026-08-09, $0.43). Left to the model,
117
+ * the parser for a known tool is a DRAFT-TIME LOTTERY on a fact nobody needed to
118
+ * guess: that run composed tsc's TTY-only pretty shape
119
+ * (`^\S+\.js:\d+:\d+ - error TS\d+:`), which matched 0 of the 67 real error lines
120
+ * the piped run actually printed, while the tool exited 2. The gates held — the
121
+ * stage read as a crashed instrument and signing was refused, correctly — but the
122
+ * refusal cost a whole authoring run to learn something the tree already knew. An
123
+ * earlier run (mslwbkz7) happened to roll the right shape. A coin-flip on an
124
+ * owned fact is not a capability question.
125
+ *
126
+ * WHAT THIS IS NOT: it does not close the parser. A stage counting something we
127
+ * have NOT measured still writes its own pattern, and that remains a real gap —
128
+ * named, not smoothed. This table is where a measured instrument fact lands, one
129
+ * at a time, with its provenance.
130
+ *
131
+ * THE TEST-COUNT FACTS (2026-08-13) landed under exactly that rule, and closed
132
+ * two of the three gaps the paragraph above used to name by hand: the executed
133
+ * count and the failure line, for both runners, are now measured facts rather
134
+ * than draft-time lotteries. Provenance rides on each entry.
135
+ *
136
+ * WHAT STAYED OUT, deliberately, because no evidence covers it:
137
+ * - a pytest FAIL-COUNT figure. A green pytest run omits the segment entirely
138
+ * (`1 passed in 0.04s`), so a figure term over it reports "never reported" on
139
+ * precisely the runs that went well. Failures are counted with the `^FAILED `
140
+ * tally instead, where no match IS zero.
141
+ * - a pytest EXECUTED count. `collected N items` is printed under `-ra` and NOT
142
+ * under `-q` (measured both ways), so no single spelling survives the modes a
143
+ * patient may configure; a stage needing it still composes its own and says so.
144
+ *
145
+ * Returns a fresh copy per call, for the reason `classGuards` does: a frozen
146
+ * constant handed to a caller that edits it is one shared table away from a
147
+ * silently changed ruler.
148
+ * @param {string} lang
149
+ * @returns {{id: string, what: string, lineMatch: string, capture: number|null, example: string, why: string}[]}
150
+ */
151
+ export function genreInstruments(lang: string): {
152
+ id: string;
153
+ what: string;
154
+ lineMatch: string;
155
+ capture: number | null;
156
+ example: string;
157
+ why: string;
158
+ }[];
105
159
  /**
106
160
  * GROUNDING for a RECORDED genre environment — the provenance half of the
107
161
  * owned-env rule, and the reason the by-value comparison is worth anything.
@@ -236,9 +290,11 @@ export function normalizeDeclaration(declaration: any): any;
236
290
  /** @typedef {{required: readonly string[], optional: readonly string[], pathParams: readonly string[], locked?: true, verdictClass: string, shape: string, asserts: string}} KindSpec */
237
291
  /** the whole menu, in ascending order of what it takes to render the verdict */
238
292
  export const VERDICT_CLASSES: readonly string[];
239
- /** declared-but-locked: selecting one is COUNTED demand, never an admission */
293
+ /** declared-but-locked: selecting one is COUNTED demand, never an admission.
294
+ * `hitl` LEFT this list at N4 slice 1 (see `src/job.js`'s twin) — the class is
295
+ * built, and its battery is below. `soft-green` waits for the judged floor. */
240
296
  export const LOCKED_CLASSES: readonly string[];
241
- /** the classes v1 actually builds — exactly one */
297
+ /** the classes v1 actually builds */
242
298
  export const LIVE_CLASSES: readonly string[];
243
299
  /**
244
300
  * The whole vocabulary, as DATA. `shape` and `asserts` are the strings the
@@ -368,6 +424,42 @@ export const TYPES_GENRE: Readonly<{
368
424
  /** no import-resolution hazard on this runner — an EMPTY list, declared,
369
425
  * never an absent field that would read as "not looked into" (F59) */
370
426
  env: readonly never[];
427
+ instruments: readonly (Readonly<{
428
+ id: "tsc-error-line";
429
+ what: "one type error, as the TypeScript checker prints it";
430
+ lineMatch: "error TS\\d+";
431
+ capture: null;
432
+ example: "src/backup.js(21,19): error TS7006: Parameter 'now' implicitly has an 'any' type.";
433
+ why: string;
434
+ }> | Readonly<{
435
+ id: "node-test-total-count";
436
+ what: "how many tests the runner EXECUTED, off the TAP summary";
437
+ lineMatch: "^# tests (\\d+)$";
438
+ capture: 1;
439
+ example: "# tests 317";
440
+ why: string;
441
+ }> | Readonly<{
442
+ id: "node-test-pass-count";
443
+ what: "how many tests passed, off the TAP summary";
444
+ lineMatch: "^# pass (\\d+)$";
445
+ capture: 1;
446
+ example: "# pass 316";
447
+ why: string;
448
+ }> | Readonly<{
449
+ id: "node-test-fail-count";
450
+ what: "how many tests failed, off the TAP summary";
451
+ lineMatch: "^# fail (\\d+)$";
452
+ capture: 1;
453
+ example: "# fail 1";
454
+ why: string;
455
+ }> | Readonly<{
456
+ id: "node-test-failed-line";
457
+ what: "one failing test, as the TAP reporter names it";
458
+ lineMatch: "^not ok \\d+ ";
459
+ capture: null;
460
+ example: "not ok 7 - edit-renotify: a non-participant edit, and edits on a pending event, ping no one";
461
+ why: string;
462
+ }>)[];
371
463
  }>;
372
464
  python: Readonly<{
373
465
  suppressions: readonly (Readonly<{
@@ -393,43 +485,77 @@ export const TYPES_GENRE: Readonly<{
393
485
  join: ":";
394
486
  why: string;
395
487
  }>[];
488
+ instruments: readonly (Readonly<{
489
+ id: "mypy-error-line";
490
+ what: "one type error, as mypy prints it";
491
+ lineMatch: " error: ";
492
+ capture: null;
493
+ example: "packages/spawner/src/aurora_spawner/timeout_policy.py:89: error: Statement is unreachable [unreachable]";
494
+ why: string;
495
+ }> | Readonly<{
496
+ id: "pytest-pass-count";
497
+ what: "how many tests passed, off pytest's final counts line";
498
+ lineMatch: "(\\d+) passed";
499
+ capture: 1;
500
+ example: "= 1 failed, 2690 passed, 3 skipped, 18 deselected, 1775 warnings in 326.12s (0:05:26) =";
501
+ why: string;
502
+ }> | Readonly<{
503
+ id: "pytest-failed-line";
504
+ what: "one failing test, as pytest's short summary names it";
505
+ lineMatch: "^FAILED ";
506
+ capture: null;
507
+ example: "FAILED packages/soar/tests/test_agent_registry_deprecation.py::TestAgentRegistryDeprecation::test_registry_and_discovery_equivalent_results";
508
+ why: string;
509
+ }>)[];
396
510
  }>;
397
511
  }>;
398
512
  }>;
399
- /**
400
- * THE GUARD BATTERY, KEYED BY VERDICT CLASS (hamr's ruling, PRD v1.57 §2).
401
- *
402
- * D5's battery was genre-keyed data. Under class-keyed interviews it has no
403
- * genre to hang from, and the ruling gives it the same home the interview took:
404
- * **the battery attaches to the verdict class the user picked** — not to a
405
- * problem-genre label, and not per catalogue KIND.
406
- *
407
- * WHY THE CLASS. What a battery is FOR is the class of dishonesty the class of
408
- * VERDICT admits. A green job is a job whose *done* is claimed to be
409
- * machine-checkable, so it carries the green battery whatever problem it came
410
- * from — that is the anti-suppression obligation the F87 genre earned, and it
411
- * must not travel with a label the interview no longer asks for.
412
- *
413
- * ATTACHMENT POINT vs CONTENTS, and the split is the whole implementation:
414
- * - the battery's STRUCTURE and its un-removability key off the CLASS. That
415
- * is this table: which guards exist, what they assert, which slot is the
416
- * model's (`fill`), and which params are ours.
417
- * - the battery's CONTENTS fill in at COMPOSITION (`compose`), because a
418
- * suppression pattern, a file extension and a checker's escape hatch belong
419
- * to the TOOL the declaration names, and nothing before composition knows
420
- * that tool. `classGuards` resolves them from the language data below.
421
- *
422
- * A LOCKED class carries `guards: null`, not `[]`. Absent is never empty (F59):
423
- * `[]` would read as "this class needs no guards", which is exactly the sentence
424
- * D5 exists to make unsayable. Nothing ever reaches it — admission refuses a
425
- * locked class before its battery is asked for — and `classGuards` throws rather
426
- * than hand back nothing if anything ever does.
427
- * @type {Record<string, {locked: boolean, guards: readonly any[]|null}>}
428
- */
429
- export const CLASS_BATTERIES: Record<string, {
430
- locked: boolean;
431
- guards: readonly any[] | null;
513
+ export const CLASS_BATTERIES: Readonly<{
514
+ green: Readonly<{
515
+ locked: false;
516
+ guards: readonly (Readonly<{
517
+ name: "changed-from-seed";
518
+ kind: "files-changed";
519
+ params: Readonly<{
520
+ requireNonEmpty: true;
521
+ }>;
522
+ compose: readonly never[];
523
+ fill: readonly string[];
524
+ }> | Readonly<{
525
+ name: "no-suppressions";
526
+ kind: "pattern-absent-in-diff";
527
+ params: Readonly<{}>;
528
+ compose: readonly string[];
529
+ fill: readonly never[];
530
+ }>)[];
531
+ }>;
532
+ 'soft-green': Readonly<{
533
+ locked: true;
534
+ guards: null;
535
+ }>;
536
+ hitl: Readonly<{
537
+ locked: false;
538
+ guards: readonly (Readonly<{
539
+ name: "changed-from-seed";
540
+ kind: "files-changed";
541
+ params: Readonly<{
542
+ requireNonEmpty: true;
543
+ }>;
544
+ compose: readonly never[];
545
+ fill: readonly string[];
546
+ }> | Readonly<{
547
+ name: "no-suppressions";
548
+ kind: "pattern-absent-in-diff";
549
+ params: Readonly<{}>;
550
+ compose: readonly string[];
551
+ fill: readonly never[];
552
+ }>)[];
553
+ }>;
432
554
  }>;
555
+ /** the kinds NO ONE runs as an in-run ruler — ruling 5's law, as data. A
556
+ * declaration that offers one is a red rather than a normalization: the signer
557
+ * must not read one thing and have the runner store another. */
558
+ export const NEVER_OFFERED_KINDS: readonly string[];
433
559
  export type Red = {
434
560
  code: string;
435
561
  path: string;
@@ -81,14 +81,16 @@ export function refuseLockedKind(kind: string): Refusal;
81
81
  * @param {{answers: Record<string|number, any>, repoPath?: string|null, lang: string,
82
82
  * verdictType?: string|null,
83
83
  * questions?: Record<string|number, string>|null, generate?: Function, provider?: any,
84
- * seedRef?: string|null, scout?: any, listing?: any,
84
+ * seedRef?: string|null, scout?: any, listing?: any, ceilingUsd?: number|null,
85
+ * onPhase?: (phase: string, data?: any) => void,
86
+ * onCall?: (call: {label: string, costUsd: number|null, unpricedRounds: number}) => void,
85
87
  * seedFn?: Function, scoutFn?: Function, listingFn?: Function,
86
88
  * authorFn?: Function, authorOpts?: object}} o
87
89
  * @returns {Promise<{ok: boolean, refusal: Refusal|null, verdictType: string|null,
88
90
  * closeDecl: any, seedRef: string|null, authoring: any, reds: Red[], stop: string|null,
89
91
  * cost: any, interview: any}>}
90
92
  */
91
- export function authorCloseForJob({ answers, repoPath, lang, verdictType, questions, generate, provider, seedRef, scout, listing, seedFn, scoutFn, listingFn, authorFn, authorOpts, }: {
93
+ export function authorCloseForJob({ answers, repoPath, lang, verdictType, questions, generate, provider, seedRef, scout, listing, ceilingUsd, onPhase, onCall, seedFn, scoutFn, listingFn, authorFn, authorOpts, }: {
92
94
  answers: Record<string | number, any>;
93
95
  repoPath?: string | null;
94
96
  lang: string;
@@ -99,6 +101,13 @@ export function authorCloseForJob({ answers, repoPath, lang, verdictType, questi
99
101
  seedRef?: string | null;
100
102
  scout?: any;
101
103
  listing?: any;
104
+ ceilingUsd?: number | null;
105
+ onPhase?: (phase: string, data?: any) => void;
106
+ onCall?: (call: {
107
+ label: string;
108
+ costUsd: number | null;
109
+ unpricedRounds: number;
110
+ }) => void;
102
111
  seedFn?: Function;
103
112
  scoutFn?: Function;
104
113
  listingFn?: Function;
@@ -91,13 +91,15 @@ export function defaultSurveyor({ workdir, granted, auditPath, ctx }: {
91
91
  *
92
92
  * @param {{workdir: string, provider?: any,
93
93
  * rounds?: number, minBytes?: number, blobMax?: number, maxTokens?: number, ctx?: boolean,
94
- * attempts?: number,
94
+ * attempts?: number, ceilingUsd?: number|null,
95
+ * onCall?: (call: {label: string, costUsd: number|null, unpricedRounds: number}) => void,
95
96
  * createLoop?: (o: {system: string, policy: any, onLlmResult: any, provider: any}) => any,
96
97
  * createSurveyor?: (o: {workdir: string, granted: readonly string[], ctx: boolean}) => Promise<any>}} o
97
98
  * @returns {Promise<Survey & {raw: string, raws: ReturnType<typeof scrubRaw>[],
98
- * calls: {label: string, costUsd: number|null, unpricedRounds: number}[]}>}
99
+ * calls: {label: string, costUsd: number|null, unpricedRounds: number}[],
100
+ * budgetStop: 'cap-halt'|'pricing-red'|null}>}
99
101
  */
100
- export function runAuthorScout({ workdir, provider, rounds, minBytes, blobMax, maxTokens, ctx, attempts, createLoop, createSurveyor, }: {
102
+ export function runAuthorScout({ workdir, provider, rounds, minBytes, blobMax, maxTokens, ctx, attempts, ceilingUsd, onCall, createLoop, createSurveyor, }: {
101
103
  workdir: string;
102
104
  provider?: any;
103
105
  rounds?: number;
@@ -106,6 +108,12 @@ export function runAuthorScout({ workdir, provider, rounds, minBytes, blobMax, m
106
108
  maxTokens?: number;
107
109
  ctx?: boolean;
108
110
  attempts?: number;
111
+ ceilingUsd?: number | null;
112
+ onCall?: (call: {
113
+ label: string;
114
+ costUsd: number | null;
115
+ unpricedRounds: number;
116
+ }) => void;
109
117
  createLoop?: (o: {
110
118
  system: string;
111
119
  policy: any;
@@ -125,6 +133,7 @@ export function runAuthorScout({ workdir, provider, rounds, minBytes, blobMax, m
125
133
  costUsd: number | null;
126
134
  unpricedRounds: number;
127
135
  }[];
136
+ budgetStop: "cap-halt" | "pricing-red" | null;
128
137
  }>;
129
138
  /**
130
139
  * `git ls-tree -r --name-only <seed>` — the files as of the SEED COMMIT.
@@ -249,6 +258,16 @@ export const SURVEY_CAUSES: Readonly<{
249
258
  NON_OBJECT: "non-object";
250
259
  /** valid JSON, no content — F59's whole point, and a SEMANTIC failure */
251
260
  EMPTY_OBJECT: "empty-object";
261
+ /**
262
+ * THE SURVEY WAS NEVER ASKED FOR: the operator's money ceiling was already
263
+ * spent when the first attempt came due, so no call was made. Named as its own
264
+ * cause for the reason this enum exists at all — a new route to ABSENT has to
265
+ * be named, and naming it is the moment somebody decides whether it retries.
266
+ * This one does not, and cannot: a retry is precisely what the cap forbade.
267
+ * It is deliberately ABSENT of the model's own doing, and the prose says so —
268
+ * "the scout did not complete" would blame a model that never spoke.
269
+ */
270
+ NOT_FUNDED: "not-funded";
252
271
  }>;
253
272
  /**
254
273
  * THE MALFORMED CLASS — the only causes a retry fires on.
package/types/clock.d.ts CHANGED
@@ -53,8 +53,11 @@ export function isWallTimeout(err: any, clock: Clock): boolean;
53
53
  * run. `closeStages`: how many stages the job's close runs (W5) — each one gets
54
54
  * the FULL `closeTimeoutMs`, so this is the multiplier on the overshoot, not a
55
55
  * decoration. Defaults to 1, the single-predicate close. `now`: injected for
56
- * tests — the default is the real clock. `priorElapsedMs`: time this attempt's
57
- * PREDECESSOR already consumed (see below).
56
+ * tests — the default is the real clock, and it stays injectable precisely so
57
+ * every test here can drive time deterministically without a sleep. That default
58
+ * is MONOTONIC (fact 4 above), not `Date.now`: a wall-clock jump — a suspend, an
59
+ * NTP step, a hand-set date — must not be able to reach a signed deadline.
60
+ * `priorElapsedMs`: time this attempt's PREDECESSOR already consumed (see below).
58
61
  * @returns {Clock}
59
62
  */
60
63
  export function createClock({ maxWallMs, closeStages, now, priorElapsedMs }?: {
@@ -97,7 +97,8 @@ export function guardNames(closeDecl: any, verdictType: string): string[];
97
97
  * @param {any[]} stages declared stage descriptors, already validated
98
98
  * @param {(s: string) => string} [redact] the scrub, applied at THIS boundary
99
99
  * @param {{timeoutMs?: number, cwd?: string, seedRef?: string,
100
- * seedTrees?: any, gapCap?: number, maxBuffer?: number, baselineMode?: 'auto'|'worktree'}} [opts]
100
+ * seedTrees?: any, gapCap?: number, maxBuffer?: number, baselineMode?: 'auto'|'worktree',
101
+ * humanRuling?: {decision: string, text?: string|null}|null}} [opts]
101
102
  * @returns {Promise<any>}
102
103
  */
103
104
  export function runDeclaredStages(stages: any[], redact?: (s: string) => string, opts?: {
@@ -108,6 +109,10 @@ export function runDeclaredStages(stages: any[], redact?: (s: string) => string,
108
109
  gapCap?: number;
109
110
  maxBuffer?: number;
110
111
  baselineMode?: "auto" | "worktree";
112
+ humanRuling?: {
113
+ decision: string;
114
+ text?: string | null;
115
+ } | null;
111
116
  }): Promise<any>;
112
117
  /**
113
118
  * The trend reader's input for ONE close verdict, whichever executor produced
@@ -160,11 +165,64 @@ export const DECLARED_GAP_PREFIX: "close: ";
160
165
  * it; because every declared line carries the prefix, it designates the stage's
161
166
  * whole judged output rather than a hand-picked slice of it. */
162
167
  export const DECLARED_GAP_KEEP: string;
163
- /** The verdict class a DECLARED close may claim. Hard, and by CONSTRUCTION
164
- * rather than by assertion: every live kind is a mechanical command whose
165
- * measurement is the truth, and the two judgment kinds are locked out at the
166
- * catalogue (M2) and absent from the executor (M1). Named as data so the job
167
- * validator reads one hierarchy table rather than hard-coding a class. */
168
+ /**
169
+ * The close verdict word for a run WAITING on a person (N4 §1.3/§1.4). A
170
+ * literal, exported, because three readers key on it — the runner's pause
171
+ * branch, the ledger's excluded set, and the trend reader's blind rule — and
172
+ * three hand-spelled copies of one terminal is how they come to disagree.
173
+ *
174
+ * It is not in `CLOSE_FAULTS` and must never be added: a fault says the close
175
+ * could not render a verdict, and this says the close is not FINISHED rendering
176
+ * one. The first escalates; the second is a checkpoint the operator returns to.
177
+ */
178
+ export const HUMAN_PAUSE: "human-pause";
179
+ /**
180
+ * The RUN-level terminal names the hitl class mints one layer up from
181
+ * `HUMAN_PAUSE` (N4 §1.3–§1.5): the checkpoint, and the honest refusal of the
182
+ * operator's rerun input. Spelled once here, beside the close-verdict word they
183
+ * translate, for the same reason `HUMAN_PAUSE` is — the emitters (`planrun.js`),
184
+ * the ledger's excluded set, the resume reader (`reuse.js`), and the runner
185
+ * script all key on them, and hand-spelled copies of one terminal is how they
186
+ * come to disagree.
187
+ *
188
+ * There were three (2026-08-17): `hitl-cancel` was the signer's own terminal and
189
+ * is DELETED with the door it belonged to. A person who does not want to carry on
190
+ * now PAUSES — the same checkpoint, resumable, retired by the TTL if nobody comes
191
+ * back — so nothing in this tree mints that name any more. The ledger keeps the
192
+ * bare string in its excluded set so a spine written before this change still
193
+ * reads as governance rather than as a capability gap; that is a READER's
194
+ * backward compatibility, and deliberately not a constant a writer could reach.
195
+ */
196
+ export const HITL_PAUSE: "hitl-pause";
197
+ export const HITL_DECISION_RED: "hitl-decision-red";
198
+ /**
199
+ * The terminals above that leave the run WAITING ON A PERSON — as a list, minted
200
+ * beside the names it holds so a reader keys on membership rather than on a
201
+ * spelling, and a rename here travels to every reader for free.
202
+ *
203
+ * It is deliberately NOT `reuse.js`'s `CHECKPOINT_OUTCOMES`, which is the wider
204
+ * RESUME list: every stop that left work on disk and an allowance unspent, money
205
+ * and time included. Those are governance stops the reuse loop is meant to try
206
+ * again under its remaining tries; this is the half no further attempt can
207
+ * change, because the allowance still unspent is a human answer. `CHECKPOINT_OUTCOMES`
208
+ * is composed FROM this list so the two can never disagree about which is which.
209
+ *
210
+ * `HITL_DECISION_RED` is not here: it is a verdict already rendered on the operator's
211
+ * own input, not a question still open.
212
+ */
213
+ export const HUMAN_CHECKPOINTS: readonly string[];
214
+ /** The verdict classes a DECLARED close may claim. Named as data so the job
215
+ * validator reads one hierarchy table rather than hard-coding a class.
216
+ *
217
+ * `hard` is by CONSTRUCTION: every mechanical kind is a command whose measurement
218
+ * is the truth. `hitl` joined it at N4 slice 1, and only because `human-confirms`
219
+ * is genuinely LIVE — the widening and the kind go in one commit, or this table
220
+ * admits a class the executor cannot render. The `soft` class is still absent:
221
+ * `judged-floor` is locked, so no declaration can reach above hitl.
222
+ *
223
+ * The direction that matters is unchanged. This says which class a declaration
224
+ * MAY claim; `closeCeiling` says which class its stages actually NEED. A pick
225
+ * below the ceiling is still the silent upgrade `class-ceiling` refuses. */
168
226
  export const DECLARED_CLOSE_CLASSES: readonly string[];
169
227
  export type Red = {
170
228
  code: string;
package/types/index.d.ts CHANGED
@@ -8,13 +8,13 @@ export { validatePlan, stageClose, EXIT_TYPES, MAX_EXITS_PER_STEP, MAX_PLAN_STEP
8
8
  export { snapshotScope, evalExits } from "./exits.js";
9
9
  export { BRIDGE_SCHEMA, validateBridge, deriveStatus, listingRow, loadGate, mintBridge, appendGreen, appendRed, loadBridge, loadRegistry, saveBridge, makeRegistry, registryExists } from "./bridges.js";
10
10
  export { renderListing, selectionPrompt } from "./selection.js";
11
- export { validateEnvelope, resolveTrySpec, resolveReuse, reuseSpecHash, selectBridge, runReuse, REUSE_GRADED_RED, readResume, resumeTreeGate } from "./reuse.js";
11
+ export { validateEnvelope, resolveTrySpec, resolveReuse, reuseSpecHash, selectBridge, runReuse, REUSE_GRADED_RED, readResume, resumeTreeGate, CHECKPOINT_OUTCOMES, PAUSE_TTL_MS, checkpointAgeGate } from "./reuse.js";
12
12
  export { classifyIncidents, foldLedger, ledgerDeltas, updateLedger, LEDGER_CLASSES } from "./ledger.js";
13
13
  export { workBranchName, prepareWorkBranch, WORK_BRANCH_PREFIX, WORK_BRANCH_RE } from "./workbranch.js";
14
- export { runDeclaredClose, runStage, seedRead, seedAtHead, seedListing, changedSet, makeSeedTrees, LIVE_KINDS, STOP_FAULTS, JUDGED_MARKER, EXIT_GREEN, EXIT_RED, EXIT_STOP } from "./kinds.js";
15
- export { validateDeclaration, normalizeDeclaration, KIND_CATALOGUE, CATALOGUE_KINDS, CATALOGUE_LIVE_KINDS, LOCKED_KINDS, TYPES_GENRE, TYPES_GENRE_TEMPLATE, GENRE_LANGUAGES, genreEnv, genreOwnedEnvNames, DIRECTIONS, BASELINES, MAX_STAGES, VERDICT_CLASSES, LOCKED_CLASSES, LIVE_CLASSES, CLASS_BATTERIES, classGuards, closeCeiling } from "./authoring.js";
14
+ export { runDeclaredClose, runStage, seedRead, seedAtHead, seedListing, changedSet, makeSeedTrees, LIVE_KINDS, STOP_FAULTS, JUDGED_MARKER, EXIT_GREEN, EXIT_RED, EXIT_STOP, HUMAN_DECISIONS, SEED_EXEMPT_KINDS, normalizeHumanRuling } from "./kinds.js";
15
+ export { validateDeclaration, normalizeDeclaration, KIND_CATALOGUE, CATALOGUE_KINDS, CATALOGUE_LIVE_KINDS, LOCKED_KINDS, TYPES_GENRE, TYPES_GENRE_TEMPLATE, GENRE_LANGUAGES, genreEnv, genreOwnedEnvNames, genreInstruments, DIRECTIONS, BASELINES, MAX_STAGES, VERDICT_CLASSES, LOCKED_CLASSES, LIVE_CLASSES, CLASS_BATTERIES, classGuards, closeCeiling, NEVER_OFFERED_KINDS } from "./authoring.js";
16
16
  export { runAuthorScout, buildSeedListing, seedFileList, classifySurvey, AUTHOR_SCOUT_VERBS, SCOUT_ATTEMPTS, SURVEY_CAUSES, SCOUT_RETRY_CAUSES } from "./authorscout.js";
17
17
  export { scrubRaw, RAW_PERSIST_MAX, RAW_TRIM_MARKER } from "./text.js";
18
18
  export { authorClose, authorPrompt, declarationSchema, makeLoopGenerate, MAX_REVISIONS, QUESTION_SETS, GREEN_QUESTIONS, CLASS_STATEMENTS, questionsFor, requiredAnswersFor } from "./authorflow.js";
19
- export { validateCloseDecl, runDeclaredStages, declaredStages, isDeclaredClose, guardNames, closeGrade, DECLARED_GENRES, DECLARED_GAP_PREFIX, DECLARED_GAP_KEEP, DECLARED_CLOSE_CLASSES, CLOSE_DECL_FIELDS } from "./declaredclose.js";
19
+ export { validateCloseDecl, runDeclaredStages, declaredStages, isDeclaredClose, guardNames, closeGrade, DECLARED_GENRES, DECLARED_GAP_PREFIX, DECLARED_GAP_KEEP, DECLARED_CLOSE_CLASSES, CLOSE_DECL_FIELDS, HUMAN_PAUSE, HITL_PAUSE, HITL_DECISION_RED, HUMAN_CHECKPOINTS } from "./declaredclose.js";
20
20
  export { runInterview, authorCloseForJob, assembleSpec, prepareSigning, refusalEvents, refuseLockedKind, GENRE, REFUSAL_LIB, REFUSAL_CATEGORY, AUTHORED_SPEC_FIELDS } from "./authorjob.js";
package/types/job.d.ts CHANGED
@@ -158,6 +158,11 @@ export const LOCKED_TOOLS: readonly string[];
158
158
  * pattern: disclosure ≠ admission), so the ledger counts the demand and the
159
159
  * non-code rung later fills a declared slot instead of reshaping the schema. */
160
160
  export const VERDICT_TYPES: readonly string[];
161
+ /** N4 slice 1: `hitl` is ADMITTED — the class whose *done* needs a person runs
162
+ * through the same signed spec, the same agent-authored plan and the same
163
+ * arbiter as a green job (the nine rulings, 2026-08-07; the three-button surface,
164
+ * 2026-08-12). `soft-green` stays declared-but-locked until its judged floor is
165
+ * built and proven (slice 2): a wobbly ruler must not mint anything. */
161
166
  export const LOCKED_VERDICTS: readonly string[];
162
167
  export const CADENCE_UNITS: readonly string[];
163
168
  /** SP-2: API-first; local deferred (PRD §5/§8). `clipipe-subscription` (F42,