bareloop 0.41.0 → 0.43.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 +109 -1
- package/README.md +13 -21
- package/bareloop.context.md +97 -34
- package/package.json +4 -3
- package/src/authorflow.js +337 -29
- package/src/authoring.js +92 -7
- package/src/authorjob.js +84 -16
- package/src/authorreadout.js +89 -5
- package/src/authorrun.js +14 -5
- package/src/authorscout.js +108 -0
- package/src/declaredclose.js +25 -14
- package/src/facts.js +317 -0
- package/src/factwords.js +129 -0
- package/src/inputlook.js +301 -0
- package/src/interviewrun.js +0 -1
- package/src/job.js +40 -12
- package/src/jobblock.js +7 -2
- package/src/kinds.js +84 -3
- package/src/labelscan.js +170 -0
- package/src/pagefetch.js +125 -0
- package/src/panel/authorroutes.js +121 -34
- package/src/panel/authorsession.js +154 -45
- package/src/panel/index.html +845 -490
- package/src/panel/jobplan.js +34 -11
- package/src/panel/runroutes.js +163 -5
- package/src/panel/scheduler.js +156 -0
- package/src/panel/schedules.js +667 -0
- package/src/panel/schedulestart.js +243 -0
- package/src/panel/server.js +467 -48
- package/src/planrun.js +42 -9
- package/src/providerrows.js +3 -3
- package/src/reviewdoor.js +37 -0
- package/src/rubricstep.js +804 -0
- package/src/runlist.js +35 -0
- package/src/schedulewords.js +296 -0
- package/src/source.js +166 -1
- package/src/trigger.js +48 -0
- package/src/triggerclock.js +127 -0
- package/src/triggerfiles.js +215 -0
- package/src/triggerledger.js +79 -0
- package/src/u-readout.js +1 -1
- package/src/userrun.js +20 -9
- package/types/authorflow.d.ts +267 -13
- package/types/authoring.d.ts +29 -1
- package/types/authorjob.d.ts +7 -5
- package/types/authorreadout.d.ts +27 -2
- package/types/authorscout.d.ts +70 -0
- package/types/declaredclose.d.ts +5 -3
- package/types/facts.d.ts +71 -0
- package/types/factwords.d.ts +42 -0
- package/types/inputlook.d.ts +238 -0
- package/types/job.d.ts +8 -1
- package/types/jobblock.d.ts +8 -1
- package/types/labelscan.d.ts +38 -0
- package/types/pagefetch.d.ts +71 -0
- package/types/panel/authorroutes.d.ts +34 -1
- package/types/panel/authorsession.d.ts +55 -14
- package/types/panel/jobplan.d.ts +12 -4
- package/types/panel/runroutes.d.ts +32 -1
- package/types/panel/scheduler.d.ts +17 -0
- package/types/panel/schedules.d.ts +412 -0
- package/types/panel/schedulestart.d.ts +106 -0
- package/types/panel/server.d.ts +145 -14
- package/types/planrun.d.ts +2 -0
- package/types/providerrows.d.ts +2 -2
- package/types/reviewdoor.d.ts +27 -0
- package/types/rubricstep.d.ts +286 -0
- package/types/runlist.d.ts +20 -0
- package/types/schedulewords.d.ts +135 -0
- package/types/source.d.ts +94 -0
- package/types/trigger.d.ts +37 -0
- package/types/triggerclock.d.ts +52 -0
- package/types/triggerfiles.d.ts +93 -0
- package/types/triggerledger.d.ts +35 -0
- package/types/userrun.d.ts +11 -0
package/types/panel/server.d.ts
CHANGED
|
@@ -116,7 +116,7 @@ export function legDividersFor(spineRecords: any[], parts: any[]): {
|
|
|
116
116
|
*
|
|
117
117
|
* The table (outcome → reason / next / buttons) is PANEL-BUILD.md P5 item 1. The
|
|
118
118
|
* Resume button appears only when `o.resume` says the engine would accept it; "Reuse workflow"
|
|
119
|
-
* (replaces P5 item 3, 2026-10-03
|
|
119
|
+
* (replaces P5 item 3, 2026-10-03; one door on every ending since 2026-10-15) starts a NEW run.
|
|
120
120
|
* @param {{outcome: string|null, stopReason: string|null, spentUsd: number|null, budgetUsd: number|null, lastEscalation?: any}} summary
|
|
121
121
|
* @param {{died: boolean, lastThing: string|null}} death
|
|
122
122
|
* @param {{resume?: {ok: boolean, why?: string}|null, destinationRefused?: string|null, moneyHalt?: boolean,
|
|
@@ -155,6 +155,28 @@ export function endedFor(summary: {
|
|
|
155
155
|
label: string;
|
|
156
156
|
}[];
|
|
157
157
|
} | null;
|
|
158
|
+
/**
|
|
159
|
+
* RULED 2026-10-15 (Remove from Needs you): the ONE place a run's Needs-you state is decided. `Accept` (a live door) is never removable and never ages out.
|
|
160
|
+
* A `Resume` tag leaves when the person removed it AFTER (or at) the stop it is for — a removal covers only the ending it was made on, so a later stop
|
|
161
|
+
* brings the run back — or after `needsYouDays`. `removedMs` is the newest removal that covers the current ending (or null), `expired` is true when only
|
|
162
|
+
* the age rule took a Resume run out.
|
|
163
|
+
* @param {{live: boolean, records: any[], resume: {ok?: boolean}|null|undefined, stoppedAt: string|null, nowMs: number, removedMs?: number}} f
|
|
164
|
+
* @returns {{needs: 'Accept'|'Resume'|null, removedMs: number|null, expired: boolean}}
|
|
165
|
+
*/
|
|
166
|
+
export function needsStateFor(f: {
|
|
167
|
+
live: boolean;
|
|
168
|
+
records: any[];
|
|
169
|
+
resume: {
|
|
170
|
+
ok?: boolean;
|
|
171
|
+
} | null | undefined;
|
|
172
|
+
stoppedAt: string | null;
|
|
173
|
+
nowMs: number;
|
|
174
|
+
removedMs?: number;
|
|
175
|
+
}): {
|
|
176
|
+
needs: "Accept" | "Resume" | null;
|
|
177
|
+
removedMs: number | null;
|
|
178
|
+
expired: boolean;
|
|
179
|
+
};
|
|
158
180
|
/**
|
|
159
181
|
* The Resume route's reader (P5 item 2): the listed row plus the resume plan, from the
|
|
160
182
|
* ONE {@link resumePlanFor} the Ended block asks. `null` when the runid is not listed
|
|
@@ -184,6 +206,43 @@ export function getStopContext(runid: string, opts?: {
|
|
|
184
206
|
live: boolean;
|
|
185
207
|
spineExists: boolean;
|
|
186
208
|
} | null;
|
|
209
|
+
/**
|
|
210
|
+
* The Remove-from-Needs-you route's reader (RULED 2026-10-15): the listed row and the Needs-you tag the runs list shows for it right now
|
|
211
|
+
* (`summarizeRow`, the one rule). `null` when the runid is not listed.
|
|
212
|
+
* @param {string} runid
|
|
213
|
+
* @param {{ home?: string, now?: number }} [opts]
|
|
214
|
+
* @returns {{row: any, needs: 'Accept'|'Resume'|null}|null}
|
|
215
|
+
*/
|
|
216
|
+
export function getNeedsContext(runid: string, opts?: {
|
|
217
|
+
home?: string;
|
|
218
|
+
now?: number;
|
|
219
|
+
}): {
|
|
220
|
+
row: any;
|
|
221
|
+
needs: "Accept" | "Resume" | null;
|
|
222
|
+
} | null;
|
|
223
|
+
/**
|
|
224
|
+
* The ONE rule for a run's Needs-you tag (P9 v2 E): `Resume` when the engine would accept a resume (the SAME `resumePlanFor` answer the Run
|
|
225
|
+
* tab's Resume card shows, already asked once per row by `endedForRow`), until the run has been stopped `needsYouDays` (exactly that old is out;
|
|
226
|
+
* no readable stop time stays in). `Accept` comes from {@link doorWaiting} (T Part 8), asked in `summarizeRow`, never here.
|
|
227
|
+
* @param {{ok?: boolean}|null|undefined} resume @param {string|null} stoppedAt @param {number} nowMs
|
|
228
|
+
* @returns {'Accept'|'Resume'|null}
|
|
229
|
+
*/
|
|
230
|
+
export function needsTag(resume: {
|
|
231
|
+
ok?: boolean;
|
|
232
|
+
} | null | undefined, stoppedAt: string | null, nowMs: number): "Accept" | "Resume" | null;
|
|
233
|
+
/**
|
|
234
|
+
* One entry per job, newest activity first: `headRunid` is the job's newest run BY TIME (never "the first row in server order"), `activityMs` the
|
|
235
|
+
* newest KNOWN time over its runs (`stoppedAt`, else `at`), `quiet` only when that time is known and older than the quiet limit. A job with a live
|
|
236
|
+
* run is never quiet; an unknown age is never guessed into quiet.
|
|
237
|
+
* @param {any[]} rows `listRuns` rows @param {number} nowMs
|
|
238
|
+
* @returns {{job: string, headRunid: string|null, quiet: boolean, activityMs: number|null}[]}
|
|
239
|
+
*/
|
|
240
|
+
export function summarizeJobs(rows: any[], nowMs: number): {
|
|
241
|
+
job: string;
|
|
242
|
+
headRunid: string | null;
|
|
243
|
+
quiet: boolean;
|
|
244
|
+
activityMs: number | null;
|
|
245
|
+
}[];
|
|
187
246
|
/**
|
|
188
247
|
* `GET /api/runs` — every listed run, NEWEST FIRST BY `at` (never by file/
|
|
189
248
|
* append order — a backfill scan appends rows in sorted-PATH order, which
|
|
@@ -197,12 +256,53 @@ export function getStopContext(runid: string, opts?: {
|
|
|
197
256
|
* SAME payload by job client-side (`groupRunsByJob` in `index.html`) rather
|
|
198
257
|
* than a second server-side endpoint, so the glyph/checkType mapping is
|
|
199
258
|
* still computed in exactly one place.
|
|
200
|
-
* @param {{ home?: string }} [opts]
|
|
259
|
+
* @param {{ home?: string, now?: number }} [opts] `now` (ms) is injectable for the Needs-you age rule
|
|
201
260
|
* @returns {any[]}
|
|
202
261
|
*/
|
|
203
262
|
export function listRuns(opts?: {
|
|
204
263
|
home?: string;
|
|
264
|
+
now?: number;
|
|
205
265
|
}): any[];
|
|
266
|
+
/**
|
|
267
|
+
* `GET /api/runs` (P9 v2 F): `{runs, jobs, limits}`. The server decides every state the left list draws — `live`, `needs`, each job's head run and
|
|
268
|
+
* quiet flag, the limits — and the page works out nothing. `scheduled` is the triggers piece (PRD v1.99, T Part 7).
|
|
269
|
+
* @param {{ home?: string, now?: number, schedules?: ReturnType<typeof createScheduleDoor> }} [opts]
|
|
270
|
+
*/
|
|
271
|
+
export function runsListPayload(opts?: {
|
|
272
|
+
home?: string;
|
|
273
|
+
now?: number;
|
|
274
|
+
schedules?: ReturnType<typeof createScheduleDoor>;
|
|
275
|
+
}): {
|
|
276
|
+
runs: any[];
|
|
277
|
+
jobs: {
|
|
278
|
+
job: string;
|
|
279
|
+
headRunid: string | null;
|
|
280
|
+
quiet: boolean;
|
|
281
|
+
activityMs: number | null;
|
|
282
|
+
}[];
|
|
283
|
+
scheduled: any[];
|
|
284
|
+
gaveUp: any[];
|
|
285
|
+
limits: Readonly<{
|
|
286
|
+
quietDays: 30;
|
|
287
|
+
olderRuns: 7;
|
|
288
|
+
needsYouDays: 7;
|
|
289
|
+
}>;
|
|
290
|
+
};
|
|
291
|
+
/**
|
|
292
|
+
* T Part 8 — what the Accept route needs: the run's row, whether its runner is alive, whether it waits at its review door
|
|
293
|
+
* ({@link doorWaiting}), and the signed spec it was judged by (the file and hash `run-u --door --approve` takes).
|
|
294
|
+
* @param {string} runid @param {{ home?: string }} opts
|
|
295
|
+
* @returns {{row: any, live: boolean, waiting: boolean, specPath: string|null, specHash: string|null}|null}
|
|
296
|
+
*/
|
|
297
|
+
export function getAcceptContext(runid: string, opts?: {
|
|
298
|
+
home?: string;
|
|
299
|
+
}): {
|
|
300
|
+
row: any;
|
|
301
|
+
live: boolean;
|
|
302
|
+
waiting: boolean;
|
|
303
|
+
specPath: string | null;
|
|
304
|
+
specHash: string | null;
|
|
305
|
+
} | null;
|
|
206
306
|
/**
|
|
207
307
|
* `GET /api/runs/:runid` — the full replay for the Run tab: steps (or
|
|
208
308
|
* iterations), counters, summary-box fields. Looks `runid` up in the run
|
|
@@ -210,11 +310,12 @@ export function listRuns(opts?: {
|
|
|
210
310
|
* header); `null` when the runid is not in the list at all (caller renders
|
|
211
311
|
* 404).
|
|
212
312
|
* @param {string} runid
|
|
213
|
-
* @param {{ home?: string }} [opts]
|
|
313
|
+
* @param {{ home?: string, schedules?: ReturnType<typeof createScheduleDoor> }} [opts]
|
|
214
314
|
* @returns {any|null}
|
|
215
315
|
*/
|
|
216
316
|
export function getRunDetail(runid: string, opts?: {
|
|
217
317
|
home?: string;
|
|
318
|
+
schedules?: ReturnType<typeof createScheduleDoor>;
|
|
218
319
|
}): any | null;
|
|
219
320
|
/**
|
|
220
321
|
* `GET /api/runs/:runid/audit` — the Audit tab's rows, off the run's own
|
|
@@ -343,11 +444,12 @@ export function inputsTextFromSpec(spec: any, source: string): string;
|
|
|
343
444
|
* from the resolved SPEC only (a) (b) (c) — a job-start record and `none()`
|
|
344
445
|
* carry no close/writeScope/tools at all, so those stay `'not recorded'`.
|
|
345
446
|
* @param {string} runid
|
|
346
|
-
* @param {{ home?: string }} [opts]
|
|
447
|
+
* @param {{ home?: string, schedules?: ReturnType<typeof createScheduleDoor> }} [opts]
|
|
347
448
|
* @returns {any|null}
|
|
348
449
|
*/
|
|
349
450
|
export function getRunJob(runid: string, opts?: {
|
|
350
451
|
home?: string;
|
|
452
|
+
schedules?: ReturnType<typeof createScheduleDoor>;
|
|
351
453
|
}): any | null;
|
|
352
454
|
/**
|
|
353
455
|
* The track record of a WORKFLOW: every LISTED run whose signed spec (the one its latest leg ran under) has this
|
|
@@ -395,14 +497,14 @@ export function reuseLine(record: {
|
|
|
395
497
|
} | null): string;
|
|
396
498
|
/**
|
|
397
499
|
* `start-from` (the route keeps its name) for one listed run: the card prefilled from the run's SIGNED job, which
|
|
398
|
-
*
|
|
500
|
+
* the track record (v1.101: nothing is locked, every box is open). The job boxes carry the signed values, read by the
|
|
399
501
|
* SAME readers the Job tab uses (`successFromSpec`/`guardrailsFromSpec`); the open four — Source, Destination, the
|
|
400
502
|
* $ cap and the Time cap — start at what the run had. `ok:false` when the run's signed job is not on disk (nothing
|
|
401
503
|
* to copy: change the job: Clear the card). `null` when the runid is not listed.
|
|
402
504
|
* @param {string} runid
|
|
403
505
|
* @param {{ home?: string, model?: string, provider?: string }} [opts] `model` = the Model box's current Name (the estimate counts only runs on that worker); absent = the card's own Model
|
|
404
506
|
* @returns {{ok: true, origin: {runid: string, job: string}, outcome: string|null, card: Record<string, any>, from: 'signed job',
|
|
405
|
-
*
|
|
507
|
+
* note: string|null,
|
|
406
508
|
* specHash: string, workflowKey: string, spec: any, specPath: string, specNamesModel: boolean,
|
|
407
509
|
* specWorker: {provider: string, endpoint: string, label: string},
|
|
408
510
|
* trackRecord: ReturnType<typeof trackRecordFor>, line: string}|{ok: false, error: string}|null}
|
|
@@ -420,8 +522,6 @@ export function getStartFrom(runid: string, opts?: {
|
|
|
420
522
|
outcome: string | null;
|
|
421
523
|
card: Record<string, any>;
|
|
422
524
|
from: "signed job";
|
|
423
|
-
locked: readonly string[];
|
|
424
|
-
open: readonly string[];
|
|
425
525
|
note: string | null;
|
|
426
526
|
specHash: string;
|
|
427
527
|
workflowKey: string;
|
|
@@ -439,6 +539,21 @@ export function getStartFrom(runid: string, opts?: {
|
|
|
439
539
|
ok: false;
|
|
440
540
|
error: string;
|
|
441
541
|
} | null;
|
|
542
|
+
/**
|
|
543
|
+
* T Part 3: a job's listed runs, newest first, each with its signed spec (null when not on disk), its terminal outcome and
|
|
544
|
+
* its parsed spine. The schedule door's gate (`greenFor`) reads this; nothing here builds a run context.
|
|
545
|
+
* @param {string} job
|
|
546
|
+
* @param {{ home?: string }} [opts]
|
|
547
|
+
* @returns {{runid: string, outcome: string|null, spec: any, records: any[]}[]}
|
|
548
|
+
*/
|
|
549
|
+
export function jobRunsOf(job: string, opts?: {
|
|
550
|
+
home?: string;
|
|
551
|
+
}): {
|
|
552
|
+
runid: string;
|
|
553
|
+
outcome: string | null;
|
|
554
|
+
spec: any;
|
|
555
|
+
records: any[];
|
|
556
|
+
}[];
|
|
442
557
|
/**
|
|
443
558
|
* The Reuse workflow picker's list: one entry per JOB (same-job identity = `workflowKey`, the one `getStartFrom` uses)
|
|
444
559
|
* that has at least one GREEN local run, newest green first. `runid` = that job's newest green run, so the page hands
|
|
@@ -469,7 +584,7 @@ export function listReuseJobs(opts?: {
|
|
|
469
584
|
* @param {string} id
|
|
470
585
|
* @param {{ home?: string, model?: string, provider?: string }} [opts] `model` as for {@link getStartFrom}
|
|
471
586
|
* @returns {{ok: true, origin: {runid: null, job: string, importId: string}, card: Record<string, any>, from: 'imported job',
|
|
472
|
-
*
|
|
587
|
+
* note: string|null, specHash: string, workflowKey: string, spec: any,
|
|
473
588
|
* specPath: null, trackRecord: ReturnType<typeof trackRecordFor>, line: string}|{ok: false, error: string}|null}
|
|
474
589
|
*/
|
|
475
590
|
export function getStartFromImport(id: string, opts?: {
|
|
@@ -485,8 +600,6 @@ export function getStartFromImport(id: string, opts?: {
|
|
|
485
600
|
};
|
|
486
601
|
card: Record<string, any>;
|
|
487
602
|
from: "imported job";
|
|
488
|
-
locked: readonly string[];
|
|
489
|
-
open: readonly string[];
|
|
490
603
|
note: string | null;
|
|
491
604
|
specHash: string;
|
|
492
605
|
workflowKey: string;
|
|
@@ -514,16 +627,18 @@ export function getStartFromImport(id: string, opts?: {
|
|
|
514
627
|
* only `createPanelServer` below always supplies one.
|
|
515
628
|
* @param {import('node:http').IncomingMessage} req
|
|
516
629
|
* @param {import('node:http').ServerResponse} res
|
|
517
|
-
* @param {{ home?: string, port: number, token?: string, authorRoutes?: ReturnType<typeof createAuthorRoutes>, settingsRoutes?: ReturnType<typeof createSettingsRoutes>, runRoutes?: ReturnType<typeof createRunRoutes>, importRoutes?: ReturnType<typeof createImportRoutes> }} opts
|
|
630
|
+
* @param {{ home?: string, packageJsonPath?: string, port: number, token?: string, authorRoutes?: ReturnType<typeof createAuthorRoutes>, settingsRoutes?: ReturnType<typeof createSettingsRoutes>, runRoutes?: ReturnType<typeof createRunRoutes>, importRoutes?: ReturnType<typeof createImportRoutes>, schedules?: ReturnType<typeof createScheduleDoor> }} opts
|
|
518
631
|
*/
|
|
519
632
|
export function handleRequest(req: import("node:http").IncomingMessage, res: import("node:http").ServerResponse, opts: {
|
|
520
633
|
home?: string;
|
|
634
|
+
packageJsonPath?: string;
|
|
521
635
|
port: number;
|
|
522
636
|
token?: string;
|
|
523
637
|
authorRoutes?: ReturnType<typeof createAuthorRoutes>;
|
|
524
638
|
settingsRoutes?: ReturnType<typeof createSettingsRoutes>;
|
|
525
639
|
runRoutes?: ReturnType<typeof createRunRoutes>;
|
|
526
640
|
importRoutes?: ReturnType<typeof createImportRoutes>;
|
|
641
|
+
schedules?: ReturnType<typeof createScheduleDoor>;
|
|
527
642
|
}): void;
|
|
528
643
|
/**
|
|
529
644
|
* Start the panel server. Binds `127.0.0.1` ONLY. A taken port is a LOUD,
|
|
@@ -544,8 +659,9 @@ export function handleRequest(req: import("node:http").IncomingMessage, res: imp
|
|
|
544
659
|
* @param {{ port?: number, home?: string, env?: Record<string,string|undefined>,
|
|
545
660
|
* sessionsRoot?: string, spawnFn?: (...a: any[]) => any, bareloopBin?: string,
|
|
546
661
|
* fetchImpl?: typeof fetch, settleMs?: number, userHome?: string,
|
|
547
|
-
* openFolderSpawn?: (cmd: string, args: string[], o: object) => any, platform?: string
|
|
548
|
-
*
|
|
662
|
+
* openFolderSpawn?: (cmd: string, args: string[], o: object) => any, platform?: string, packageJsonPath?: string,
|
|
663
|
+
* scheduleNow?: () => number, sessionDeps?: Record<string, any>, schedulerIntervalMs?: number, acceptWaitMs?: number }} [opts] `scheduleNow`, `sessionDeps` and `schedulerIntervalMs` are TEST SEAMS (the schedule clock; createSession's stubs; the scheduler's timer, 0 = none)
|
|
664
|
+
* @returns {Promise<{ server: import('node:http').Server, port: number, token: string, schedules: ReturnType<typeof createScheduleDoor>, scheduler: ReturnType<typeof createScheduler>, close: () => Promise<void> }>}
|
|
549
665
|
*/
|
|
550
666
|
export function createPanelServer(opts?: {
|
|
551
667
|
port?: number;
|
|
@@ -559,10 +675,17 @@ export function createPanelServer(opts?: {
|
|
|
559
675
|
userHome?: string;
|
|
560
676
|
openFolderSpawn?: (cmd: string, args: string[], o: object) => any;
|
|
561
677
|
platform?: string;
|
|
678
|
+
packageJsonPath?: string;
|
|
679
|
+
scheduleNow?: () => number;
|
|
680
|
+
sessionDeps?: Record<string, any>;
|
|
681
|
+
schedulerIntervalMs?: number;
|
|
682
|
+
acceptWaitMs?: number;
|
|
562
683
|
}): Promise<{
|
|
563
684
|
server: import("node:http").Server;
|
|
564
685
|
port: number;
|
|
565
686
|
token: string;
|
|
687
|
+
schedules: ReturnType<typeof createScheduleDoor>;
|
|
688
|
+
scheduler: ReturnType<typeof createScheduler>;
|
|
566
689
|
close: () => Promise<void>;
|
|
567
690
|
}>;
|
|
568
691
|
/**
|
|
@@ -602,13 +725,21 @@ export const DEFAULT_PORT: 4700;
|
|
|
602
725
|
*/
|
|
603
726
|
export const SOFTGREEN_ADMITTED_ISO: "2026-08-18T00:00:00.000Z";
|
|
604
727
|
export { DIED_MTIME_MS };
|
|
728
|
+
/** The named limits of the runs list, in ONE place (P9 v2 D.13): quiet after 30 days, 7 older runs shown, a Resume tag ages out after 7 days. Sent in `GET /api/runs`; the page reads them from there. */
|
|
729
|
+
export const RUNS_LIST_LIMITS: Readonly<{
|
|
730
|
+
quietDays: 30;
|
|
731
|
+
olderRuns: 7;
|
|
732
|
+
needsYouDays: 7;
|
|
733
|
+
}>;
|
|
605
734
|
/** The default/max page size for {@link getRunRounds} — tighten-only,
|
|
606
735
|
* named so a future change is a deliberate, visible edit (item 5,
|
|
607
736
|
* 2026-09-25). */
|
|
608
737
|
export const ROUNDS_PAGE_DEFAULT: 50;
|
|
609
738
|
export const ROUNDS_PAGE_MAX: 200;
|
|
739
|
+
import { createScheduleDoor } from './schedules.js';
|
|
610
740
|
import { createAuthorRoutes } from './authorroutes.js';
|
|
611
741
|
import { createSettingsRoutes } from './settingsroutes.js';
|
|
612
742
|
import { createRunRoutes } from './runroutes.js';
|
|
613
743
|
import { createImportRoutes } from './importroutes.js';
|
|
744
|
+
import { createScheduler } from './scheduler.js';
|
|
614
745
|
import { DIED_MTIME_MS } from '../runlist.js';
|
package/types/planrun.d.ts
CHANGED
|
@@ -523,6 +523,8 @@ export const FORBIDDEN_WRITE_SEGMENT_PATTERN: RegExp;
|
|
|
523
523
|
export const BOUND_REASON_MAX: 200;
|
|
524
524
|
/** the recorded reason for a step attempt whose round was cut at the output cap (F122 2A b) */
|
|
525
525
|
export const TRUNCATED_REASON: "output cut at the token limit (max_tokens)";
|
|
526
|
+
/** the plain sentence for a replan answer cut off at its length limit (hamr 2026-10-16, run mv9gm796) */
|
|
527
|
+
export const REPLAN_CUT_WORDS: "The replan answer was cut off at its length limit, so no new plan came back.";
|
|
526
528
|
export type CategorizedError = Error & {
|
|
527
529
|
category?: string;
|
|
528
530
|
lib?: string;
|
package/types/providerrows.d.ts
CHANGED
|
@@ -251,8 +251,8 @@ export function judgeRowFor(rows: readonly KeyRow[], judge: {
|
|
|
251
251
|
* the worker's own provider it calls the worker's endpoint, so a row on that endpoint with a line
|
|
252
252
|
* NAMED for the judge's model prices it ({@link ratesFor}); a judge model that is absent or names
|
|
253
253
|
* no line there keeps the worker's price (the worker's row, or none = the guess). A different
|
|
254
|
-
* provider resolves with no endpoint. The judge's KEY is chosen elsewhere (`
|
|
255
|
-
*
|
|
254
|
+
* provider resolves with no endpoint. The judge's KEY is chosen elsewhere (`judgeRowFor`:
|
|
255
|
+
* the worker's own row when the judge shares its provider), so the two can come from different rows.
|
|
256
256
|
* @param {{ provider: string, model?: string|null }} judge
|
|
257
257
|
* @param {string|null|undefined} workerProvider
|
|
258
258
|
* @param {string|null|undefined} workerBaseUrl
|
package/types/reviewdoor.d.ts
CHANGED
|
@@ -4,6 +4,33 @@
|
|
|
4
4
|
* @param {any[]} events the run's spine, parsed
|
|
5
5
|
* @returns {any|null} */
|
|
6
6
|
export function doorRecordOf(events: any[]): any | null;
|
|
7
|
+
/**
|
|
8
|
+
* Was this run's door ACCEPTED, honoured? A `door-decision` record with `decision: 'accept'` and `honoured: true`
|
|
9
|
+
* (written by {@link answerReviewDoor}, whichever surface asked: the CLI, or the panel's Accept). Pure, off the
|
|
10
|
+
* run's spine. A refused accept (`honoured: false`) does not count.
|
|
11
|
+
* @param {any[]} events the run's spine, parsed
|
|
12
|
+
* @returns {boolean}
|
|
13
|
+
*/
|
|
14
|
+
export function doorAccepted(events: any[]): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* T D.2 — a SCHEDULED run's green is held until the person accepts it (T10): a run that carries a `trigger.json` (a scheduled
|
|
17
|
+
* start wrote it) and holds no honoured accept. One shared predicate: `getStartFrom` reads its outcome as `'green-held'` (so
|
|
18
|
+
* the Reuse start refuses it unchanged), `listReuseJobs` skips it, and the schedule gate does not count it. A hand run is never held.
|
|
19
|
+
* @param {any[]} events the run's spine, parsed @param {any} triggerRec the run's `trigger.json`, or null
|
|
20
|
+
* @returns {boolean}
|
|
21
|
+
*/
|
|
22
|
+
export function heldScheduled(events: any[], triggerRec: any): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Is this run WAITING for the person's Accept? Its spine holds a door record, the door has not expired ({@link doorAgeGate}),
|
|
25
|
+
* and no honoured `accept` or `rerun` decision follows it (a `pause` keeps the same three doors open). One owner: the runs
|
|
26
|
+
* list's Needs-you `Accept` tag, the Run tab's Accept button and the scheduled NEXT line all read this.
|
|
27
|
+
* @param {any[]} events the run's spine, parsed
|
|
28
|
+
* @param {{now?: () => number}} [opts]
|
|
29
|
+
* @returns {boolean}
|
|
30
|
+
*/
|
|
31
|
+
export function doorWaiting(events: any[], opts?: {
|
|
32
|
+
now?: () => number;
|
|
33
|
+
}): boolean;
|
|
7
34
|
/**
|
|
8
35
|
* IS THE DOOR STILL OPEN? The same 60-day TTL a hitl checkpoint keeps
|
|
9
36
|
* (`PAUSE_TTL_MS`) and deliberately the same NUMBER — the door replaced `cancel`
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one statement of the step-file shape, in plain words. The worker's goal and the composer's prompt both carry it.
|
|
3
|
+
* @returns {string}
|
|
4
|
+
*/
|
|
5
|
+
export function stepFileContract(): string;
|
|
6
|
+
/**
|
|
7
|
+
* What the worker is told about each line, from the close that will grade it (PART 1b item 7): a FACTS line gets its
|
|
8
|
+
* facts and its count; a TEXT line that follows a facts line is told its numbers come from that line's quotes. Written by code from
|
|
9
|
+
* the signed parts, never by a model. A line with no rubric-step stage gets nothing here.
|
|
10
|
+
* @param {any} closeDecl @returns {{line: number, text: string}[]}
|
|
11
|
+
*/
|
|
12
|
+
export function lineBriefs(closeDecl: any): {
|
|
13
|
+
line: number;
|
|
14
|
+
text: string;
|
|
15
|
+
}[];
|
|
16
|
+
/**
|
|
17
|
+
* The worker's goal for a rubric job on local files — written by code from the person's own numbered lines, never by a
|
|
18
|
+
* model. It states everything the close will judge about the FORM of the answer (the file, the keys, the quotes); what
|
|
19
|
+
* each line asks for stays in the person's own words, with its `~` rules beneath it.
|
|
20
|
+
* @param {{jobLines: {n: number, text: string, rule: string}[], files: {label: string, rel: string}[], confirmedGoal?: string|null, closeDecl?: any}} o
|
|
21
|
+
* `confirmedGoal` — the one goal sentence the person confirmed in the confirm turn, kept as the plan line
|
|
22
|
+
* `closeDecl` — the drafted close: with it, each line is briefed by what its stage checks (a facts line or a text line, `lineBriefs`)
|
|
23
|
+
* @returns {string}
|
|
24
|
+
*/
|
|
25
|
+
export function rubricGoal({ jobLines, files, confirmedGoal, closeDecl }: {
|
|
26
|
+
jobLines: {
|
|
27
|
+
n: number;
|
|
28
|
+
text: string;
|
|
29
|
+
rule: string;
|
|
30
|
+
}[];
|
|
31
|
+
files: {
|
|
32
|
+
label: string;
|
|
33
|
+
rel: string;
|
|
34
|
+
}[];
|
|
35
|
+
confirmedGoal?: string | null;
|
|
36
|
+
closeDecl?: any;
|
|
37
|
+
}): string;
|
|
38
|
+
/**
|
|
39
|
+
* The SHAPE of a `rubric-step` stage's parameters — what a part may carry — and nothing about which class is allowed in
|
|
40
|
+
* this build (that is `checkRubricParts`, which also sees the whole job). Pure, never throws.
|
|
41
|
+
* @param {unknown} p the stage's `params`
|
|
42
|
+
* @param {string} at the path prefix for reds, e.g. `stages[1].params`
|
|
43
|
+
* @returns {ShapeRed[]}
|
|
44
|
+
*/
|
|
45
|
+
export function rubricStepShapeReds(p: unknown, at: string): ShapeRed[];
|
|
46
|
+
/** the labels of the inputs a step's `cited` parts name (each once, in order) @param {any} params @returns {string[]} */
|
|
47
|
+
export function citedLabels(params: any): string[];
|
|
48
|
+
/**
|
|
49
|
+
* The rubric spec for ONE step, built from its parameters and the sha256 of each input it cites (taken from the source
|
|
50
|
+
* manifest at run start — a rubric is rebuilt per run because the inputs belong to the run, not to the signed job).
|
|
51
|
+
* `happened` is bareguard's own foundational check; the `text` floor below it stops a step file whose only key is junk
|
|
52
|
+
* from passing a rubric that has no countable part.
|
|
53
|
+
* @param {{step: number, parts: any[]}} params
|
|
54
|
+
* @param {Record<string, string>} inputShas label -> sha256 hex, for every label the step cites
|
|
55
|
+
* @returns {Record<string, any>} a spec for bareguard's `createRubric`
|
|
56
|
+
*/
|
|
57
|
+
export function buildStepSpec(params: {
|
|
58
|
+
step: number;
|
|
59
|
+
parts: any[];
|
|
60
|
+
}, inputShas: Record<string, string>): Record<string, any>;
|
|
61
|
+
/**
|
|
62
|
+
* The step file's bytes as the close reads them: the parsed JSON object, or WHY there is none. A file cut off mid-write
|
|
63
|
+
* parses to nothing (reason `not-json`); text cut off INSIDE an otherwise valid JSON object cannot be told from a short
|
|
64
|
+
* answer — that limit is documented, not hidden.
|
|
65
|
+
* @param {string|null} bytes the file's text, or null when it does not exist
|
|
66
|
+
* @returns {{obj: Record<string, any>, why: null}|{obj: null, why: 'missing'|'not-json'|'not-object'}}
|
|
67
|
+
*/
|
|
68
|
+
export function parseStepFile(bytes: string | null): {
|
|
69
|
+
obj: Record<string, any>;
|
|
70
|
+
why: null;
|
|
71
|
+
} | {
|
|
72
|
+
obj: null;
|
|
73
|
+
why: "missing" | "not-json" | "not-object";
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* The step file as bareguard's rubric reads it: a flat object. `text` stays `text`; each label in `cites` becomes the field
|
|
77
|
+
* `cites:<label>` (the name a `cited` check reads its claims from). Nothing else in the file is read.
|
|
78
|
+
* @param {Record<string, any>} obj
|
|
79
|
+
* @param {string[]} [countLabels] labels whose claim COUNT a minClaims/maxClaims part reads
|
|
80
|
+
* @param {any} [factPart] the step's `fact` part: its `results` become claims (text built by code) under `cites:<source>`
|
|
81
|
+
* @returns {Record<string, any>}
|
|
82
|
+
*/
|
|
83
|
+
export function flattenStep(obj: Record<string, any>, countLabels?: string[], factPart?: any): Record<string, any>;
|
|
84
|
+
/**
|
|
85
|
+
* One bareguard gap as a sentence the worker can act on. The numbers and names are bareguard's own measurements and the
|
|
86
|
+
* person's signed limits, never anything this module infers; a gap this table does not know falls back to bareguard's own
|
|
87
|
+
* rendering, so nothing is ever dropped.
|
|
88
|
+
* @param {number} step @param {string} why why there was no object, when there was none
|
|
89
|
+
* @param {any} g a bareguard gap
|
|
90
|
+
* @param {any} [params] the stage's parameters (a fact step words its gaps by fact)
|
|
91
|
+
* @returns {string}
|
|
92
|
+
*/
|
|
93
|
+
export function plainStepGap(step: number, why: string, g: any, params?: any): string;
|
|
94
|
+
/**
|
|
95
|
+
* Grade ONE step: build the rubric, run it over the step file's fields, and say what happened in the close's own terms.
|
|
96
|
+
* Pure of the filesystem (the runner in src/kinds.js reads the files). `stopped` = the instrument failed (never a red).
|
|
97
|
+
* @param {{params: {step: number, parts: any[]}, bytes: string|null, outputBytes: string|null, inputs: Record<string, string>,
|
|
98
|
+
* factQuotes?: Record<number, string[]>, factMissing?: number[]}} o
|
|
99
|
+
* `factQuotes` maps an earlier fact line's number to the quotes its (already checked) step file holds — what a prose step's numbers are tied to
|
|
100
|
+
* `factMissing` lists the earlier fact lines whose step file is not there (yet): a normal red, never an instrument fault
|
|
101
|
+
* `inputs` maps each cited label to its frozen TEXT; its sha256 is taken here from that text, and bareguard compares it to
|
|
102
|
+
* the manifest's recorded sha via `inputShas`.
|
|
103
|
+
* @param {Record<string, string>} inputShas the manifest's recorded sha256 per cited label
|
|
104
|
+
* @returns {Promise<{verdict: 'green'|'red'|'stopped', gapLines: string[], fault: string|null, detail: Record<string, any>}>}
|
|
105
|
+
*/
|
|
106
|
+
export function gradeStep({ params, bytes, outputBytes, inputs, factQuotes, factMissing }: {
|
|
107
|
+
params: {
|
|
108
|
+
step: number;
|
|
109
|
+
parts: any[];
|
|
110
|
+
};
|
|
111
|
+
bytes: string | null;
|
|
112
|
+
outputBytes: string | null;
|
|
113
|
+
inputs: Record<string, string>;
|
|
114
|
+
factQuotes?: Record<number, string[]>;
|
|
115
|
+
factMissing?: number[];
|
|
116
|
+
}, inputShas: Record<string, string>): Promise<{
|
|
117
|
+
verdict: "green" | "red" | "stopped";
|
|
118
|
+
gapLines: string[];
|
|
119
|
+
fault: string | null;
|
|
120
|
+
detail: Record<string, any>;
|
|
121
|
+
}>;
|
|
122
|
+
/**
|
|
123
|
+
* The labels of a job's numbered inputs, or null when it carries none (a caller that has no inputs in hand skips the label rule).
|
|
124
|
+
* @param {unknown} inputs @returns {string[]|null}
|
|
125
|
+
*/
|
|
126
|
+
export function inputLabelsOf(inputs: unknown): string[] | null;
|
|
127
|
+
/**
|
|
128
|
+
* R11 — the drafting-time rules for the `rubric-step` stages of a declaration, each a red in the person's plain words that
|
|
129
|
+
* names the job line and ends "Nothing spent." where nothing was. Pure; never throws. Judged parts are RED in this build
|
|
130
|
+
* (the judge arrives in the next one): the sorting is still asked for, so a part that needs the judge is named as such
|
|
131
|
+
* instead of being approximated by a count.
|
|
132
|
+
* - a stage serves exactly the one job line it names (`step` = its only `fromLine`), and no line has two stages;
|
|
133
|
+
* - a part with no class (`none`) cannot be counted or checked against a quote;
|
|
134
|
+
* - a `judged` part needs the judge; a `guard` part is about web sources and the job has no web input;
|
|
135
|
+
* - two countable parts of ONE line that no text can satisfy together (a minimum above a maximum) are a contradiction,
|
|
136
|
+
* naming both parts and both numbers;
|
|
137
|
+
* - a `cited` part names a label the person's inputs do not have.
|
|
138
|
+
* @param {any[]} stages the declaration's stages
|
|
139
|
+
* @param {{inputLabels?: string[]|null, red: (code: string, path: string, detail: string, extra?: object) => void}} o
|
|
140
|
+
* `inputLabels` absent = the label rule is not run (a caller with no inputs in hand)
|
|
141
|
+
*/
|
|
142
|
+
export function checkRubricParts(stages: any[], { inputLabels, red }: {
|
|
143
|
+
inputLabels?: string[] | null;
|
|
144
|
+
red: (code: string, path: string, detail: string, extra?: object) => void;
|
|
145
|
+
}): void;
|
|
146
|
+
/** the ~ rules of one job line, one string each (`rules` when the line has the array, else the joined `rule` split on "; ") @param {any} l @returns {string[]} */
|
|
147
|
+
export function lineRules(l: any): string[];
|
|
148
|
+
/**
|
|
149
|
+
* PART 1b, RF16 + RF17 — the rules that need the person's own job lines. Only a close built for REQUIRED FACTS is held to them (a
|
|
150
|
+
* close with a fact part, or any part that says which `~` rules it carries out): an older Part 1a close is left as it was signed.
|
|
151
|
+
* - every `~` rule of every job line is carried out by a part (its number in the part's `rules`), or is listed in `refused` with
|
|
152
|
+
* its `rule` number, or its whole line is refused: a rule that is none of those was silently dropped, and that is a red;
|
|
153
|
+
* - a number the AI made out of the person's words (a bound the person did not write) must be marked `aiProposal`, and a time
|
|
154
|
+
* limit the AI proposes must be a range (`between`), never one-sided — "not a red-eye" must not let a 10 PM flight through.
|
|
155
|
+
* @param {any[]} stages @param {{jobLines?: any[]|null, refused?: any, red: (code: string, path: string, detail: string, extra?: object) => void}} o
|
|
156
|
+
*/
|
|
157
|
+
export function checkRubricRules(stages: any[], { jobLines, refused, red }: {
|
|
158
|
+
jobLines?: any[] | null;
|
|
159
|
+
refused?: any;
|
|
160
|
+
red: (code: string, path: string, detail: string, extra?: object) => void;
|
|
161
|
+
}): void;
|
|
162
|
+
/**
|
|
163
|
+
* PART 1c L3 - the person's own words win over the AI's reading of them, settled by CODE before anything is validated or signed:
|
|
164
|
+
* - a limit on a fact whose bounds are all in the words the person wrote (the line, its `~` rules, an answer they gave) is the
|
|
165
|
+
* person's, so it is NOT marked "AI's proposal" (smv710w8c3wdh: the plan called the person's own range the AI's);
|
|
166
|
+
* - a time range the AI proposed while the person wrote ONE explicit positive time range ("between 07:00 and 23:00") on that line
|
|
167
|
+
* is replaced by exactly that range (smv710w8c3wdh: the plan said 5:00 AM). Only when it is unambiguous: one such range in the
|
|
168
|
+
* line's rules and one AI-proposed `between` time fact on the line; a rule with a negation ("not between ...") is never read as a range;
|
|
169
|
+
* - a `~` rule is a check or under Not checked, never both: a `refused` entry for a rule that a part of its own line carries is dropped.
|
|
170
|
+
* Pure; returns a new declaration, the input untouched. The model is told the same in the brief; this makes it true either way.
|
|
171
|
+
* @param {any} declaration @param {any[]|null|undefined} jobLines @returns {any}
|
|
172
|
+
*/
|
|
173
|
+
export function settlePersonsWords(declaration: any, jobLines: any[] | null | undefined): any;
|
|
174
|
+
/**
|
|
175
|
+
* PART 1b — put the number tie on every prose step. A rubric-step stage with no fact part that comes AFTER one or more fact
|
|
176
|
+
* stages gets exactly one `numbersFromFacts` part naming those lines; one the model wrote is replaced. Pure; returns a new
|
|
177
|
+
* declaration (the input is untouched). The model never writes this part: it is code's, so a draft cannot omit it.
|
|
178
|
+
* @param {any} declaration @returns {any}
|
|
179
|
+
*/
|
|
180
|
+
export function withFactBindings(declaration: any): any;
|
|
181
|
+
/**
|
|
182
|
+
* The ~ rules the drafter listed under Not checked (`refused` entries that name a `rule`), each as one line in the person's own
|
|
183
|
+
* words: `line N: "<the rule as written>" — <the drafter's reason>` (PART 1b, RF6 / RF16).
|
|
184
|
+
* @param {any} closeDecl @param {any[]|null|undefined} jobLines @returns {string[]}
|
|
185
|
+
*/
|
|
186
|
+
export function ruleNotChecked(closeDecl: any, jobLines: any[] | null | undefined): string[];
|
|
187
|
+
/**
|
|
188
|
+
* The Not-checked lines code owns for the rubric-step stages of a close: a prose step's CONTENT is judged by the person at
|
|
189
|
+
* Accept, and the card says so (PART 1b, RF5). One line per prose step (a stage with no fact part).
|
|
190
|
+
* @param {any} closeDecl @returns {string[]}
|
|
191
|
+
*/
|
|
192
|
+
export function proseNotChecked(closeDecl: any): string[];
|
|
193
|
+
/**
|
|
194
|
+
* One countable part as a plain sentence, written by code from the part's signed fields (never from the model's words), so the
|
|
195
|
+
* plan card and the close are one thing seen twice.
|
|
196
|
+
* @param {any} part @returns {string}
|
|
197
|
+
*/
|
|
198
|
+
export function partSentence(part: any): string;
|
|
199
|
+
/**
|
|
200
|
+
* The checks a signed close actually runs, per job line, in plain code-written sentences: one per countable part of every
|
|
201
|
+
* rubric-step stage. This is the ONE reader both the plan card and the sign-time invariant use.
|
|
202
|
+
* @param {any} closeDecl
|
|
203
|
+
* @returns {{line: number, text: string, covers: number[]}[]}
|
|
204
|
+
*/
|
|
205
|
+
export function checksOfClose(closeDecl: any): {
|
|
206
|
+
line: number;
|
|
207
|
+
text: string;
|
|
208
|
+
covers: number[];
|
|
209
|
+
}[];
|
|
210
|
+
/**
|
|
211
|
+
* Reconcile the CONFIRMED plan with the close the composer actually wrote. The plan card after drafting shows exactly
|
|
212
|
+
* the close's own checks (`checksOfClose`); every confirmed check that no part carries out (no part lists its number in
|
|
213
|
+
* `covers`) is moved to Not checked, in the person's words, with the reason. A check can therefore never be shown and then
|
|
214
|
+
* silently dropped (run mv5bk400: "lists 3 releases" was confirmed, then left out of the signed close without a word).
|
|
215
|
+
* @param {{confirmed: {text: string, fromLine: number[]|null}[], notChecked: string[], closeDecl: any, jobLines?: any[]|null}} o
|
|
216
|
+
* `jobLines` — the person's numbered lines, so a ~ rule the drafter listed as Not checked reads in the person's own words
|
|
217
|
+
* @returns {{checkItems: {text: string, fromLine: number[]}[], notChecked: string[], moved: {text: string, fromLine: number[]|null}[]}}
|
|
218
|
+
*/
|
|
219
|
+
export function reconcileRubricPlan({ confirmed, notChecked, closeDecl, jobLines }: {
|
|
220
|
+
confirmed: {
|
|
221
|
+
text: string;
|
|
222
|
+
fromLine: number[] | null;
|
|
223
|
+
}[];
|
|
224
|
+
notChecked: string[];
|
|
225
|
+
closeDecl: any;
|
|
226
|
+
jobLines?: any[] | null;
|
|
227
|
+
}): {
|
|
228
|
+
checkItems: {
|
|
229
|
+
text: string;
|
|
230
|
+
fromLine: number[];
|
|
231
|
+
}[];
|
|
232
|
+
notChecked: string[];
|
|
233
|
+
moved: {
|
|
234
|
+
text: string;
|
|
235
|
+
fromLine: number[] | null;
|
|
236
|
+
}[];
|
|
237
|
+
};
|
|
238
|
+
/**
|
|
239
|
+
* The sign-time invariant: the checks the person was shown (`shown`, from the plan card) are exactly the checks the signed
|
|
240
|
+
* close runs (`checksOfClose`), per line. Pure.
|
|
241
|
+
* @param {{text: string, fromLine: number[]|null}[]} shown @param {any} closeDecl
|
|
242
|
+
* @returns {{ok: true}|{ok: false, error: string}}
|
|
243
|
+
*/
|
|
244
|
+
export function planMatchesClose(shown: {
|
|
245
|
+
text: string;
|
|
246
|
+
fromLine: number[] | null;
|
|
247
|
+
}[], closeDecl: any): {
|
|
248
|
+
ok: true;
|
|
249
|
+
} | {
|
|
250
|
+
ok: false;
|
|
251
|
+
error: string;
|
|
252
|
+
};
|
|
253
|
+
/**
|
|
254
|
+
* The frozen TEXT of the named inputs, read the way the runner reads them: the source door's record (`source.json`, one level
|
|
255
|
+
* above the tree) names each input's file and sha256, and a file whose bytes no longer match is not returned. Used at DRAFTING
|
|
256
|
+
* (the drafter reads the input, the early tests run on it) and at run start (the backstop). Never throws.
|
|
257
|
+
* @param {string} workdir the frozen tree @param {string[]} labels
|
|
258
|
+
* @returns {Promise<{ok: true, texts: Record<string, string>}|{ok: false, why: string}>}
|
|
259
|
+
*/
|
|
260
|
+
export function readFrozenInputs(workdir: string, labels: string[]): Promise<{
|
|
261
|
+
ok: true;
|
|
262
|
+
texts: Record<string, string>;
|
|
263
|
+
} | {
|
|
264
|
+
ok: false;
|
|
265
|
+
why: string;
|
|
266
|
+
}>;
|
|
267
|
+
/** where the per-line step files live, inside the job's tree; `copyOut` delivers them with the rest of `output/` */
|
|
268
|
+
export const STEP_DIR: "output/steps";
|
|
269
|
+
export function stepFileRel(n: number): string;
|
|
270
|
+
/** the largest step file the close reads: a bigger one is a stop, never silently truncated (bareguard's own source cap) */
|
|
271
|
+
export const STEP_MAX_BYTES: number;
|
|
272
|
+
/** the closed set of classes a part is sorted into; `none` = "I could not sort this one" (a red, in plain words, never a guess) */
|
|
273
|
+
export const PART_CLASSES: readonly string[];
|
|
274
|
+
/**
|
|
275
|
+
* The counted/quoted checks a `countable` part may name, with the fields each needs — read off bareguard's own rule table
|
|
276
|
+
* (`rubricVocabulary`): the names are bareguard's, so a check this build cannot run is inexpressible, not rejected late.
|
|
277
|
+
* (`max`/`min` need a numeric field the step file does not have, so they are not offered.)
|
|
278
|
+
* @type {Readonly<Record<string, readonly string[]>>}
|
|
279
|
+
*/
|
|
280
|
+
export const COUNT_CHECKS: Readonly<Record<string, readonly string[]>>;
|
|
281
|
+
export function sha256Of(b: string | Buffer): string;
|
|
282
|
+
export type ShapeRed = {
|
|
283
|
+
code: string;
|
|
284
|
+
path: string;
|
|
285
|
+
detail: string;
|
|
286
|
+
};
|