bareloop 0.42.0 → 0.44.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 +88 -0
- package/bareloop.context.md +103 -41
- package/package.json +2 -2
- package/src/authorflow.js +26 -11
- package/src/authoring.js +1 -1
- package/src/authorjob.js +33 -15
- package/src/authorreadout.js +7 -6
- package/src/declaredclose.js +6 -3
- package/src/draftspend.js +20 -2
- package/src/facts.js +54 -9
- package/src/factwords.js +58 -6
- package/src/inputlook.js +38 -3
- package/src/interviewrun.js +0 -1
- package/src/job.js +39 -12
- package/src/kinds.js +5 -0
- package/src/pagedropwords.js +64 -0
- package/src/pagemap.js +264 -0
- package/src/pagerules.js +319 -0
- package/src/panel/authorroutes.js +138 -60
- package/src/panel/authorsession.js +88 -32
- package/src/panel/index.html +1251 -522
- package/src/panel/jobplan.js +4 -2
- package/src/panel/runroutes.js +188 -6
- 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 +1234 -68
- package/src/panel/status.js +33 -0
- package/src/panelmoney.js +29 -0
- package/src/planrun.js +92 -11
- package/src/promptregisters.js +4 -0
- package/src/providerrows.js +3 -3
- package/src/replay.js +118 -7
- package/src/reviewdoor.js +37 -0
- package/src/rubricstep.js +123 -11
- package/src/runlist.js +37 -1
- package/src/schedulewords.js +299 -0
- package/src/source.js +18 -0
- package/src/thinking.js +63 -2
- 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/userrun.js +34 -21
- package/types/authorflow.d.ts +42 -6
- package/types/authorjob.d.ts +10 -2
- package/types/declaredclose.d.ts +3 -1
- package/types/draftspend.d.ts +27 -1
- package/types/facts.d.ts +15 -0
- package/types/factwords.d.ts +26 -3
- package/types/inputlook.d.ts +15 -0
- package/types/job.d.ts +8 -1
- package/types/kinds.d.ts +5 -0
- package/types/pagedropwords.d.ts +26 -0
- package/types/pagemap.d.ts +154 -0
- package/types/pagerules.d.ts +86 -0
- package/types/panel/authorroutes.d.ts +50 -14
- package/types/panel/authorsession.d.ts +37 -12
- 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 +297 -15
- package/types/panel/status.d.ts +51 -0
- package/types/panelmoney.d.ts +5 -0
- package/types/planrun.d.ts +2 -0
- package/types/providerrows.d.ts +2 -2
- package/types/replay.d.ts +21 -1
- package/types/reviewdoor.d.ts +27 -0
- package/types/rubricstep.d.ts +57 -1
- package/types/runlist.d.ts +24 -1
- package/types/schedulewords.d.ts +137 -0
- package/types/source.d.ts +11 -0
- package/types/thinking.d.ts +39 -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 +4 -0
package/src/userrun.js
CHANGED
|
@@ -54,7 +54,8 @@ import { resolveJudge } from './judged.js';
|
|
|
54
54
|
// path uses (never a second one) and keeps its patient the way it left it.
|
|
55
55
|
import { readResume, resumeTreeGate, checkpointAgeGate, writeRunGreenRow, CHECKPOINT_OUTCOMES, PAUSE_TTL_MS } from './reuse.js';
|
|
56
56
|
// PRD item 28's provider factory (src/providers.js): the WORKER provider's
|
|
57
|
-
// ctor/
|
|
57
|
+
// ctor/param-gating come from here now (its key variable and price come from the
|
|
58
|
+
// Settings row, src/providerrows.js) — one seam instead
|
|
58
59
|
// of an `if (provider === …)` scattered across this script. PRD item 32.2
|
|
59
60
|
// moved the JUDGE onto this SAME factory: it used to be separately pinned
|
|
60
61
|
// below to a hardcoded Anthropic constructor at the judged tier because the
|
|
@@ -303,6 +304,7 @@ class ExitSignal extends Error {
|
|
|
303
304
|
* @property {string} seed
|
|
304
305
|
* @property {string} spineName
|
|
305
306
|
* @property {string} [into] see `RunOpts.into`
|
|
307
|
+
* @property {boolean} [refreeze] a FRESH `--spec` run: fetch the web inputs again AFTER the run is listed (never on resume/door/decide)
|
|
306
308
|
* @property {string|null} model
|
|
307
309
|
* @property {string|null} providerKey
|
|
308
310
|
* @property {string|null} readShim
|
|
@@ -492,7 +494,8 @@ async function execute(ctx) {
|
|
|
492
494
|
const REGISTRY_TAIL = (ctx.registry ?? null) !== null ? ` --registry ${(ctx.registry ?? null)} --workflow ${(ctx.workflow ?? null) ?? spec.job}` : '';
|
|
493
495
|
|
|
494
496
|
const WORKDIR = target.workdir;
|
|
495
|
-
|
|
497
|
+
// `let`: a fresh run's refetch of its web inputs commits a NEW seed (below, after the run is listed)
|
|
498
|
+
let SEED = target.seed;
|
|
496
499
|
const specHash = jobSpecHash(spec);
|
|
497
500
|
// the re-invocation commands this engine prints: a bundle names its own door and hash,
|
|
498
501
|
// every other caller gets today's byte-identical strings.
|
|
@@ -507,10 +510,8 @@ async function execute(ctx) {
|
|
|
507
510
|
// and tested apart from this script. The JUDGE's model is resolved separately
|
|
508
511
|
// (`resolveJudge`, below the key block): it defaults to this same resolved
|
|
509
512
|
// worker model and a signed `judge` override wins over it.
|
|
510
|
-
//
|
|
511
|
-
//
|
|
512
|
-
// `--model` FLAG's vocabulary only, sonnet/haiku, unrelated to which
|
|
513
|
-
// provider the spec names). `spec.provider` is not validateJob'd until
|
|
513
|
+
// There is no default model: a spec or flag that names none dies below with
|
|
514
|
+
// REFUSE_NAME_MODEL (the model is one ticked in Settings). `spec.provider` is not validateJob'd until
|
|
514
515
|
// runJob below, so an unrecognized value dies here with the same operator-
|
|
515
516
|
// facing message resolveWorkerModel's own errors use, rather than an
|
|
516
517
|
// unhandled throw.
|
|
@@ -1405,8 +1406,8 @@ async function execute(ctx) {
|
|
|
1405
1406
|
// token against. That made "provider-agnostic" half-true: you could run on
|
|
1406
1407
|
// another provider only if you also held an Anthropic account.
|
|
1407
1408
|
//
|
|
1408
|
-
// The WORKER's key comes from
|
|
1409
|
-
// there is one
|
|
1409
|
+
// The WORKER's key comes from its Settings row's own env name (`keyValueOf`, src/providerrows.js,
|
|
1410
|
+
// so there is one place saying which row reads which variable) and is
|
|
1410
1411
|
// ALWAYS required — the worker always runs.
|
|
1411
1412
|
//
|
|
1412
1413
|
// The JUDGE's key is required only when the close actually judges
|
|
@@ -1585,6 +1586,24 @@ async function execute(ctx) {
|
|
|
1585
1586
|
err(`WARNING: could not add this run to ~/.config/bareloop/runs.jsonl (${e.message}) — the run continues; the panel's list will be missing this row.`);
|
|
1586
1587
|
}
|
|
1587
1588
|
|
|
1589
|
+
// RUN START REFETCH (PART 1c RF22; moved here 2026-10-19, run mvez8s54: the ~18 s barebrowse fetch ran in main() BEFORE this run was
|
|
1590
|
+
// listed, so Sign & run showed nothing for 18 s). The run is listed FIRST (row above, with its pid and cap = the monthly claim), THEN
|
|
1591
|
+
// fetches: the Run tab reads "fetching the page…" while source.json has no refrozenAt at or after the row. A refusal cannot be a
|
|
1592
|
+
// `released` row (that unlists the run and its words); it SETTLES the claim at $0 and keeps the plain reason for the panel.
|
|
1593
|
+
if (ctx.refreeze === true && ctx.into !== undefined) {
|
|
1594
|
+
const fresh = await refreezeUrlInputs({ into: ctx.into, ...(deps.fetchUrl ? { fetchUrl: deps.fetchUrl } : {}) });
|
|
1595
|
+
if (!fresh.ok) {
|
|
1596
|
+
const words = /did not start/.test(fresh.error) ? fresh.error : `${fresh.error}. The run did not start. Nothing spent.`;
|
|
1597
|
+
err(`${SELECTOR}: ${fresh.error}`);
|
|
1598
|
+
if (claimedRow) {
|
|
1599
|
+
try { appendRunEvent({ runid, type: 'settled', by: runid, reason: 'refused before start', words, spentUsd: 0, spendComplete: true, at: new Date().toISOString() }, { home: claimedRow.home }); } catch { /* the exit stands; the dead pid's claim is closed by the next run */ }
|
|
1600
|
+
claimedRow = null; // settled, not released: a released leg-1 row is unlisted, and the person must see why
|
|
1601
|
+
}
|
|
1602
|
+
throw new ExitSignal(2);
|
|
1603
|
+
}
|
|
1604
|
+
if (fresh.refreshed.length > 0 && typeof fresh.seed === 'string' && fresh.seed) SEED = fresh.seed;
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1588
1607
|
const git = (/** @type {string[]} */ a) => execFileSync('git', ['-C', wd, ...a], { encoding: 'utf8' }).trim();
|
|
1589
1608
|
if (dead) {
|
|
1590
1609
|
// A RESUME is the OPPOSITE case from a cold launch: the halted run's edits are work
|
|
@@ -2055,7 +2074,7 @@ async function execute(ctx) {
|
|
|
2055
2074
|
const legDraftSpentUsd = typeof jobStartRec?.draftSpentUsd === 'number' && jobStartRec.draftSpentUsd > 0 ? jobStartRec.draftSpentUsd : null;
|
|
2056
2075
|
const legDraftSpendComplete = legDraftSpentUsd === null ? null : jobStartRec.draftSpendComplete !== false;
|
|
2057
2076
|
const spendCore = je?.spentUsd == null ? 'UNKNOWN' : `${je.spendComplete === false ? '≥' : ''}$${je.spentUsd.toFixed(4)}`;
|
|
2058
|
-
out(`spent ${moneyWithDraft(spendCore, legDraftSpentUsd, spec.budgetUsd, legDraftSpendComplete)}`);
|
|
2077
|
+
out(`spent ${moneyWithDraft(spendCore, legDraftSpentUsd, spec.budgetUsd, legDraftSpendComplete, je?.spentUsd ?? null)}`);
|
|
2059
2078
|
// FOLDED, exactly like the money line above it: on a resume the cap governs both legs
|
|
2060
2079
|
// together, and a leg-only wall next to a folded spend is two framings on one cap with
|
|
2061
2080
|
// no label to tell them apart (F83). The leg stays on the line beside it.
|
|
@@ -2517,6 +2536,7 @@ export async function main(argv, deps = {}) {
|
|
|
2517
2536
|
/** how a "go edit the spec" hint renders — `jobs/<file>` for `--job`, the
|
|
2518
2537
|
* spec's own path for `--spec` (it has no `jobs/` home to point at). */
|
|
2519
2538
|
let SPEC_DESC;
|
|
2539
|
+
let refreeze = false;
|
|
2520
2540
|
let spec;
|
|
2521
2541
|
|
|
2522
2542
|
if (jobArg !== null) {
|
|
@@ -2593,24 +2613,16 @@ export async function main(argv, deps = {}) {
|
|
|
2593
2613
|
+ 'with exactly one source-*/ sibling.');
|
|
2594
2614
|
}
|
|
2595
2615
|
const into = candidates[0];
|
|
2596
|
-
|
|
2616
|
+
const manifestRead = await readSourceManifest(into);
|
|
2597
2617
|
if (manifestRead.stop !== null) {
|
|
2598
2618
|
die(`--spec ${specPath}: ${manifestRead.code} — ${manifestRead.stop}`);
|
|
2599
2619
|
}
|
|
2600
2620
|
if (!manifestRead.present || !manifestRead.manifest) {
|
|
2601
2621
|
die(`--spec ${specPath}: ${into} carries no source.json — not a prepared copy this runner can trust`);
|
|
2602
2622
|
}
|
|
2603
|
-
// PART 1c (RF22): a FRESH run
|
|
2604
|
-
//
|
|
2605
|
-
|
|
2606
|
-
if (argFlag('resume') === null && argFlag('door') === null && argFlag('decide') === null) {
|
|
2607
|
-
const fresh = await refreezeUrlInputs({ into, ...(deps.fetchUrl ? { fetchUrl: deps.fetchUrl } : {}) });
|
|
2608
|
-
if (!fresh.ok) die(`--spec ${specPath}: ${fresh.error}`);
|
|
2609
|
-
if (fresh.refreshed.length > 0) {
|
|
2610
|
-
manifestRead = await readSourceManifest(into);
|
|
2611
|
-
if (manifestRead.stop !== null || !manifestRead.manifest) die(`--spec ${specPath}: the run copy's record could not be read after the fresh fetch`);
|
|
2612
|
-
}
|
|
2613
|
-
}
|
|
2623
|
+
// PART 1c (RF22): a FRESH run with web inputs fetches each address again before the worker starts. That happens in execute(),
|
|
2624
|
+
// AFTER the run is listed (`ctx.refreeze`); a resume / door / decision keeps the copy its first start froze.
|
|
2625
|
+
refreeze = argFlag('resume') === null && argFlag('door') === null && argFlag('decide') === null;
|
|
2614
2626
|
const seed = manifestRead.manifest.seed;
|
|
2615
2627
|
if (typeof seed !== 'string' || !seed) {
|
|
2616
2628
|
die(`--spec ${specPath}: ${into}/source.json carries no seed commit — not a prepared copy this runner can trust`);
|
|
@@ -2648,6 +2660,7 @@ export async function main(argv, deps = {}) {
|
|
|
2648
2660
|
seed: target.seed,
|
|
2649
2661
|
spineName: target.spine,
|
|
2650
2662
|
...(target.into === undefined ? {} : { into: target.into }),
|
|
2663
|
+
...(refreeze ? { refreeze: true } : {}),
|
|
2651
2664
|
model: argFlag('model'),
|
|
2652
2665
|
providerKey: argFlag('provider'),
|
|
2653
2666
|
readShim: argFlag('read-shim'),
|
package/types/authorflow.d.ts
CHANGED
|
@@ -10,12 +10,16 @@ export function linesNamedByReds(reds: Red[], declaration: any, lineNums: number
|
|
|
10
10
|
* The machine's keep-or-drop of the try-3 questions. Kept only when its line is one the previous try's reds named and its
|
|
11
11
|
* text is non-blank, at most {@link MAX_QUESTIONS}; every drop comes back with its reason, for the draft's log.
|
|
12
12
|
* @param {any} raw @param {number[]} failedLines
|
|
13
|
-
* @returns {{kept: {line: number, question: string}[], dropped: {reason: string, raw: any}[]}}
|
|
13
|
+
* @returns {{kept: {line: number, question: string, rule?: number, source?: string, ask?: 'reading'|'cant-check', reading?: string}[], dropped: {reason: string, raw: any}[]}}
|
|
14
14
|
*/
|
|
15
15
|
export function normalizeQuestions(raw: any, failedLines: number[]): {
|
|
16
16
|
kept: {
|
|
17
17
|
line: number;
|
|
18
18
|
question: string;
|
|
19
|
+
rule?: number;
|
|
20
|
+
source?: string;
|
|
21
|
+
ask?: "reading" | "cant-check";
|
|
22
|
+
reading?: string;
|
|
19
23
|
}[];
|
|
20
24
|
dropped: {
|
|
21
25
|
reason: string;
|
|
@@ -1093,8 +1097,8 @@ export const REVISE_RED_CAP: 20;
|
|
|
1093
1097
|
export const AUTHOR_MAX_TOKENS: 32000;
|
|
1094
1098
|
/** the one slot the model fills on an injected guard */
|
|
1095
1099
|
export const FILL_MARKER: "<FILL IN>";
|
|
1096
|
-
/** P7 item 5 (fwdloop am24/25): the most questions the MACHINE keeps from the try-3 drafter. The drafter is never told this number. */
|
|
1097
|
-
export const MAX_QUESTIONS:
|
|
1100
|
+
/** P7 item 5 (fwdloop am24/25): the most questions the MACHINE keeps from the try-3 drafter. The drafter is never told this number. PRD v1.107 Part 5b: three (hamr's ruling), shared with the code-forced early asks. */
|
|
1101
|
+
export const MAX_QUESTIONS: 3;
|
|
1098
1102
|
/**
|
|
1099
1103
|
* The model-visible words of the optional `questions` property — offered ONLY on the last drafting try and only after the
|
|
1100
1104
|
* two before it both failed validation (a mechanism, never a wish: the schema carries it on that one call and nowhere
|
|
@@ -1680,12 +1684,44 @@ export const PARAM_SCHEMAS: Readonly<{
|
|
|
1680
1684
|
description: string;
|
|
1681
1685
|
};
|
|
1682
1686
|
unit: {
|
|
1683
|
-
|
|
1684
|
-
|
|
1687
|
+
anyOf: ({
|
|
1688
|
+
type: string;
|
|
1689
|
+
minLength: number;
|
|
1690
|
+
minItems?: undefined;
|
|
1691
|
+
maxItems?: undefined;
|
|
1692
|
+
uniqueItems?: undefined;
|
|
1693
|
+
items?: undefined;
|
|
1694
|
+
} | {
|
|
1695
|
+
type: string;
|
|
1696
|
+
minItems: number;
|
|
1697
|
+
maxItems: number;
|
|
1698
|
+
uniqueItems: boolean;
|
|
1699
|
+
items: {
|
|
1700
|
+
type: string;
|
|
1701
|
+
minLength: number;
|
|
1702
|
+
};
|
|
1703
|
+
minLength?: undefined;
|
|
1704
|
+
})[];
|
|
1685
1705
|
description: string;
|
|
1686
1706
|
};
|
|
1687
1707
|
currency: {
|
|
1688
|
-
|
|
1708
|
+
anyOf: ({
|
|
1709
|
+
enum: string[];
|
|
1710
|
+
type?: undefined;
|
|
1711
|
+
minItems?: undefined;
|
|
1712
|
+
maxItems?: undefined;
|
|
1713
|
+
uniqueItems?: undefined;
|
|
1714
|
+
items?: undefined;
|
|
1715
|
+
} | {
|
|
1716
|
+
type: string;
|
|
1717
|
+
minItems: number;
|
|
1718
|
+
maxItems: number;
|
|
1719
|
+
uniqueItems: boolean;
|
|
1720
|
+
items: {
|
|
1721
|
+
enum: string[];
|
|
1722
|
+
};
|
|
1723
|
+
enum?: undefined;
|
|
1724
|
+
})[];
|
|
1689
1725
|
description: string;
|
|
1690
1726
|
};
|
|
1691
1727
|
phrase: {
|
package/types/authorjob.d.ts
CHANGED
|
@@ -91,8 +91,8 @@ export function refuseLockedKind(kind: string): Refusal;
|
|
|
91
91
|
* authorFn?: Function, authorOpts?: object, writeScope?: string[]|null,
|
|
92
92
|
* signerFix?: Function|any, proposeFn?: Function, compileOpts?: object,
|
|
93
93
|
* ask?: ((step: {kind: string, [k: string]: any}) => Promise<string|null>)|null,
|
|
94
|
-
* answerQuestions?: ((o: {questions: {line: number, question: string}[], dropped: {reason: string, raw: any}[], confirmed: any}) =>
|
|
95
|
-
* Promise<{jobLines: {n: number, text: string, rule?: string}[], answers: Record<string|number, any
|
|
94
|
+
* answerQuestions?: ((o: {questions: {line: number, question: string, rule?: number, source?: string, ask?: string, reading?: string}[], dropped: {reason: string, raw: any}[], confirmed: any}) =>
|
|
95
|
+
* Promise<{jobLines: {n: number, text: string, rule?: string}[], answers: Record<string|number, any>, left?: {line: number, rule: number}[]}|null>)|null,
|
|
96
96
|
* confirmGenerate?: Function|null, isRepo?: boolean,
|
|
97
97
|
* langResult?: {kind: string, candidates?: string[], [k: string]: any}|null}} o
|
|
98
98
|
* @returns {Promise<{ok: boolean, refusal: Refusal|null, verdictType: string|null,
|
|
@@ -151,6 +151,10 @@ export function authorCloseForJob({ answers, repoPath, lang, verdictType, questi
|
|
|
151
151
|
questions: {
|
|
152
152
|
line: number;
|
|
153
153
|
question: string;
|
|
154
|
+
rule?: number;
|
|
155
|
+
source?: string;
|
|
156
|
+
ask?: string;
|
|
157
|
+
reading?: string;
|
|
154
158
|
}[];
|
|
155
159
|
dropped: {
|
|
156
160
|
reason: string;
|
|
@@ -164,6 +168,10 @@ export function authorCloseForJob({ answers, repoPath, lang, verdictType, questi
|
|
|
164
168
|
rule?: string;
|
|
165
169
|
}[];
|
|
166
170
|
answers: Record<string | number, any>;
|
|
171
|
+
left?: {
|
|
172
|
+
line: number;
|
|
173
|
+
rule: number;
|
|
174
|
+
}[];
|
|
167
175
|
} | null>) | null;
|
|
168
176
|
confirmGenerate?: Function | null;
|
|
169
177
|
isRepo?: boolean;
|
package/types/declaredclose.d.ts
CHANGED
|
@@ -118,6 +118,7 @@ export function guardNames(closeDecl: any, verdictType: string): string[];
|
|
|
118
118
|
* judgeLoop?: ((o: {system: string}) => any)|null,
|
|
119
119
|
* judgeModel?: string|null,
|
|
120
120
|
* onJudgeCost?: ((c: any) => void)|null,
|
|
121
|
+
* onRubricEvidence?: ((e: any) => void)|null,
|
|
121
122
|
* callBounds?: (() => {timeoutMs?: number, deadlineMs?: number})|null}} [opts]
|
|
122
123
|
* @returns {Promise<any>}
|
|
123
124
|
*/
|
|
@@ -138,6 +139,7 @@ export function runDeclaredStages(stages: any[], redact?: (s: string) => string,
|
|
|
138
139
|
}) => any) | null;
|
|
139
140
|
judgeModel?: string | null;
|
|
140
141
|
onJudgeCost?: ((c: any) => void) | null;
|
|
142
|
+
onRubricEvidence?: ((e: any) => void) | null;
|
|
141
143
|
callBounds?: (() => {
|
|
142
144
|
timeoutMs?: number;
|
|
143
145
|
deadlineMs?: number;
|
|
@@ -187,7 +189,7 @@ export const CLOSE_DECL_FIELDS: readonly string[];
|
|
|
187
189
|
/** what a stored calibration set carries, ENUMERATED: the frozen cases and the judge
|
|
188
190
|
* tier that graded them. Both are inside the spec, so `jobSpecHash` covers both — which
|
|
189
191
|
* is the whole mechanism behind "a judge-model bump forces a full recalibration"
|
|
190
|
-
* (src/judged.js, `
|
|
192
|
+
* (src/judged.js, `resolveJudge`): the field moves, the hash moves, the signature dies,
|
|
191
193
|
* and the re-sign re-runs the gate. Anything else in there is a field nobody reads. */
|
|
192
194
|
export const CALIBRATION_FIELDS: readonly string[];
|
|
193
195
|
/**
|
package/types/draftspend.d.ts
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
* - `step-start` {no, id, label, at}
|
|
4
4
|
* - `step-end` {no, status: 'done'|'failed', label, at} (a re-opened step writes `step-reopen` {no, at} first)
|
|
5
5
|
* - `step-label` {no, label, at} (the step reads `label` from now on, status and times untouched: the thinking row's "the model thought anyway" / "can't change it" / "not confirmed")
|
|
6
|
+
* - `human` {no, source: 'confirm'|'try-3'|'look', question, answer, line?, at}: one question the person was asked and what they answered (the answer is secret-masked
|
|
7
|
+
* before it is written; the row is written only when BOTH exist, so a question nobody answered leaves no row)
|
|
6
8
|
* - `call` {no, step, label, model, thinking, thinkingSupport, thinkingStatus?, costUsd (null stays null), unpricedRounds, at}: one METERED model call
|
|
7
9
|
* (`thinking` = the tick's mode: off | on; `thinkingSupport` = bare-agent's lookup for the model: true | false | 'unverified';
|
|
8
10
|
* `thinkingStatus` = bare-agent's own verdict for the call's run: applied | unsupported | ignored | unknown, present only when thinkingMode was sent)
|
|
@@ -58,12 +60,33 @@ export function sessionDirForRow(row: {
|
|
|
58
60
|
home?: string;
|
|
59
61
|
sessionsRoot?: string;
|
|
60
62
|
}): string | null;
|
|
63
|
+
/**
|
|
64
|
+
* PRD v1.106 Part 5 Q1: one answered question as the two lines the Audit's drafting table shows under its step. ONE place owns the words.
|
|
65
|
+
* @param {{question: string, answer: string, source?: string, line?: number, at?: string}} h
|
|
66
|
+
* @returns {{question: string, answer: string, source: string, line?: number, at?: string, askedText: string, saidText: string}}
|
|
67
|
+
*/
|
|
68
|
+
export function humanRowWords(h: {
|
|
69
|
+
question: string;
|
|
70
|
+
answer: string;
|
|
71
|
+
source?: string;
|
|
72
|
+
line?: number;
|
|
73
|
+
at?: string;
|
|
74
|
+
}): {
|
|
75
|
+
question: string;
|
|
76
|
+
answer: string;
|
|
77
|
+
source: string;
|
|
78
|
+
line?: number;
|
|
79
|
+
at?: string;
|
|
80
|
+
askedText: string;
|
|
81
|
+
saidText: string;
|
|
82
|
+
};
|
|
61
83
|
/**
|
|
62
84
|
* Fold `<dir>/draft-log.jsonl` into one record per drafting step, each with its calls. A line that cannot be parsed is
|
|
63
85
|
* skipped (a torn last line must not hide the rest).
|
|
64
86
|
* @param {string} dir
|
|
65
87
|
* @returns {{no: number, id: string, label: string, status: 'running'|'done'|'failed', startedAt: string, endedAt: string|null, wallMs: number|null,
|
|
66
|
-
* calls: {label: string, model: string|null, costUsd: number|null, unpricedRounds: number, at: string}[]
|
|
88
|
+
* calls: {label: string, model: string|null, costUsd: number|null, unpricedRounds: number, at: string}[],
|
|
89
|
+
* humans: ReturnType<typeof humanRowWords>[]}[]}
|
|
67
90
|
*/
|
|
68
91
|
export function readDraftSteps(dir: string): {
|
|
69
92
|
no: number;
|
|
@@ -80,6 +103,7 @@ export function readDraftSteps(dir: string): {
|
|
|
80
103
|
unpricedRounds: number;
|
|
81
104
|
at: string;
|
|
82
105
|
}[];
|
|
106
|
+
humans: ReturnType<typeof humanRowWords>[];
|
|
83
107
|
}[];
|
|
84
108
|
/**
|
|
85
109
|
* The DRAFTING PART of a run (hamr 2026-10-06, option A): the first part of the run's views, built from the session's
|
|
@@ -109,6 +133,8 @@ export const DRAFT_LOG_FILE: "draft-log.jsonl";
|
|
|
109
133
|
* - `step-start` {no, id, label, at}
|
|
110
134
|
* - `step-end` {no, status: 'done'|'failed', label, at} (a re-opened step writes `step-reopen` {no, at} first)
|
|
111
135
|
* - `step-label` {no, label, at} (the step reads `label` from now on, status and times untouched: the thinking row's "the model thought anyway" / "can't change it" / "not confirmed")
|
|
136
|
+
* - `human` {no, source: 'confirm'|'try-3'|'look', question, answer, line?, at}: one question the person was asked and what they answered (the answer is secret-masked
|
|
137
|
+
* before it is written; the row is written only when BOTH exist, so a question nobody answered leaves no row)
|
|
112
138
|
* - `call` {no, step, label, model, thinking, thinkingSupport, thinkingStatus?, costUsd (null stays null), unpricedRounds, at}: one METERED model call
|
|
113
139
|
* (`thinking` = the tick's mode: off | on; `thinkingSupport` = bare-agent's lookup for the model: true | false | 'unverified';
|
|
114
140
|
* `thinkingStatus` = bare-agent's own verdict for the call's run: applied | unsupported | ignored | unknown, present only when thinkingMode was sent)
|
package/types/facts.d.ts
CHANGED
|
@@ -23,6 +23,14 @@ export function factClaims(part: any, results: unknown): {
|
|
|
23
23
|
quote: string;
|
|
24
24
|
values?: Record<string, string>;
|
|
25
25
|
}[];
|
|
26
|
+
/**
|
|
27
|
+
* One amount of a money fact in the fact's OWN signed forms, never a hardcoded sign: `symbolFirst` puts the currency sign before the amount
|
|
28
|
+
* ("$144") when the fact has one, else the unit after it ("144 US dollars"); not `symbolFirst` (a rule's bound) prefers the unit.
|
|
29
|
+
* @param {any} f a money fact @param {string|number} n @param {boolean} symbolFirst @returns {string}
|
|
30
|
+
*/
|
|
31
|
+
export function moneyAs(f: any, n: string | number, symbolFirst: boolean): string;
|
|
32
|
+
/** @param {any} f a fact with a rule @returns {string} the rule in words, e.g. "at most 450 US dollars" */
|
|
33
|
+
export function ruleWords(f: any): string;
|
|
26
34
|
/**
|
|
27
35
|
* One fact as a plain row, written by code from the signed fields:
|
|
28
36
|
* `fact · price — money, at most 450 US dollars, after "Price", quoted from "Flights"`.
|
|
@@ -69,3 +77,10 @@ export const FACT_OPS: readonly string[];
|
|
|
69
77
|
export const MAX_FACTS: 10;
|
|
70
78
|
/** every field a part of class `fact` may carry (the shared ones are checked by rubricStepShapeReds) */
|
|
71
79
|
export const FACT_PART_FIELDS: readonly string[];
|
|
80
|
+
/** the limits bareguard 0.24 puts on a money fact's lists (ruling #65), enforced here first so the red is ours and plain */
|
|
81
|
+
export const MAX_CURRENCIES: 3;
|
|
82
|
+
export const MAX_UNITS: 10;
|
|
83
|
+
export const MAX_UNIT_CHARS: 100;
|
|
84
|
+
export function asList(v: unknown): string[];
|
|
85
|
+
export function moneyForms(f: any): string[];
|
|
86
|
+
export function boundOk(shape: string, v: unknown): boolean;
|
package/types/factwords.d.ts
CHANGED
|
@@ -9,16 +9,35 @@ export function countExact(source: string, words: string): number;
|
|
|
9
9
|
* @param {string} source @param {string} words @returns {number}
|
|
10
10
|
*/
|
|
11
11
|
export function countPhrase(source: string, words: string): number;
|
|
12
|
+
/**
|
|
13
|
+
* What the page-word map (src/pagemap.js) KEPT and DROPPED for one input: the sets the second proof reads. A look from the old search-and-read
|
|
14
|
+
* path has no `dropped` list, so it gives null and the label is proved against the code-made list as before.
|
|
15
|
+
* @param {{facts?: any[], dropped?: (import('./pagerules.js').Dropped & {source?: string})[]}|null|undefined} look @param {string} source
|
|
16
|
+
* @returns {{labels: Set<string>, units: Set<string>, currencies: Set<string>, words: Set<string>, dropped: Map<string, import('./pagerules.js').Dropped>}|null}
|
|
17
|
+
*/
|
|
18
|
+
export function keptSetOf(look: {
|
|
19
|
+
facts?: any[];
|
|
20
|
+
dropped?: (import("./pagerules.js").Dropped & {
|
|
21
|
+
source?: string;
|
|
22
|
+
})[];
|
|
23
|
+
} | null | undefined, source: string): {
|
|
24
|
+
labels: Set<string>;
|
|
25
|
+
units: Set<string>;
|
|
26
|
+
currencies: Set<string>;
|
|
27
|
+
words: Set<string>;
|
|
28
|
+
dropped: Map<string, import("./pagerules.js").Dropped>;
|
|
29
|
+
} | null;
|
|
12
30
|
/**
|
|
13
31
|
* The reds for ONE fact part against its frozen source text.
|
|
14
|
-
* @param {{part: any, text: string, line: number|string, scan?: import('./labelscan.js').LabelScan}} o
|
|
32
|
+
* @param {{part: any, text: string, line: number|string, scan?: import('./labelscan.js').LabelScan, kept?: ReturnType<typeof keptSetOf>}} o
|
|
15
33
|
* @returns {{code: string, detail: string}[]}
|
|
16
34
|
*/
|
|
17
|
-
export function checkFactWords({ part, text, line, scan }: {
|
|
35
|
+
export function checkFactWords({ part, text, line, scan, kept }: {
|
|
18
36
|
part: any;
|
|
19
37
|
text: string;
|
|
20
38
|
line: number | string;
|
|
21
39
|
scan?: import("./labelscan.js").LabelScan;
|
|
40
|
+
kept?: ReturnType<typeof keptSetOf>;
|
|
22
41
|
}): {
|
|
23
42
|
code: string;
|
|
24
43
|
detail: string;
|
|
@@ -27,9 +46,13 @@ export function checkFactWords({ part, text, line, scan }: {
|
|
|
27
46
|
* The reds for every fact part of a declaration. A fact part whose input text is not at hand is a red: a check whose words were never
|
|
28
47
|
* proved against the source is never signed.
|
|
29
48
|
* @param {any} declaration @param {Record<string, string>|null} texts label -> frozen text
|
|
49
|
+
* @param {{facts?: any[], dropped?: any[]}|null} [look] the page-word map's report: what it kept and dropped (null = no map, the code-made list is the proof)
|
|
30
50
|
* @returns {{code: string, path: string, detail: string}[]}
|
|
31
51
|
*/
|
|
32
|
-
export function checkDeclarationWords(declaration: any, texts: Record<string, string> | null
|
|
52
|
+
export function checkDeclarationWords(declaration: any, texts: Record<string, string> | null, look?: {
|
|
53
|
+
facts?: any[];
|
|
54
|
+
dropped?: any[];
|
|
55
|
+
} | null): {
|
|
33
56
|
code: string;
|
|
34
57
|
path: string;
|
|
35
58
|
detail: string;
|
package/types/inputlook.d.ts
CHANGED
|
@@ -148,6 +148,12 @@ export function lookPrompt({ jobLines, labels, lists }: {
|
|
|
148
148
|
labels: string[];
|
|
149
149
|
lists: Record<string, string>;
|
|
150
150
|
}): string;
|
|
151
|
+
/**
|
|
152
|
+
* A fact the page-word map kept (src/pagerules.js `KeptFact`), as the look report carries it: a phrase fact holds its alternative
|
|
153
|
+
* phrases; any other holds its labels (the first is the primary), and a money fact its units and currencies.
|
|
154
|
+
* @param {import('./pagerules.js').KeptFact} k @param {string} source @returns {LookFact}
|
|
155
|
+
*/
|
|
156
|
+
export function lookFactOf(k: import("./pagerules.js").KeptFact, source: string): LookFact;
|
|
151
157
|
/**
|
|
152
158
|
* Turn the AI's raw report into a VERIFIED one, by code, at $0. A fact is carried only when: its shape is a real shape, its source is
|
|
153
159
|
* a real input, and its label is ON THE LIST for that input and shape (an id is resolved to its exact words). Anything else is moved
|
|
@@ -207,6 +213,9 @@ export const LOOK_REPORT_TOOL: "report_look";
|
|
|
207
213
|
/** how many hits one search returns at most, and how long a snippet or a read line is */
|
|
208
214
|
export const LOOK_MAX_HITS: 40;
|
|
209
215
|
export { LABEL_SHAPES };
|
|
216
|
+
/**
|
|
217
|
+
* `words` / `labels` / `unit` / `currency`: what the page-word map kept (idea A core)
|
|
218
|
+
*/
|
|
210
219
|
export type LookFact = {
|
|
211
220
|
line: number;
|
|
212
221
|
name: string;
|
|
@@ -220,6 +229,11 @@ export type LookFact = {
|
|
|
220
229
|
rule?: any;
|
|
221
230
|
aiProposal?: boolean;
|
|
222
231
|
forRule?: number;
|
|
232
|
+
reading?: import("./pagerules.js").Reading;
|
|
233
|
+
words?: string[];
|
|
234
|
+
labels?: string[];
|
|
235
|
+
unit?: string[];
|
|
236
|
+
currency?: string[];
|
|
223
237
|
};
|
|
224
238
|
export type LookNotFound = {
|
|
225
239
|
line: number;
|
|
@@ -234,5 +248,6 @@ export type LookReport = {
|
|
|
234
248
|
text?: string;
|
|
235
249
|
}[];
|
|
236
250
|
notFound: LookNotFound[];
|
|
251
|
+
dropped?: import("./pagerules.js").Dropped[];
|
|
237
252
|
};
|
|
238
253
|
import { LABEL_SHAPES } from './labelscan.js';
|
package/types/job.d.ts
CHANGED
|
@@ -99,7 +99,8 @@ export function jobSpecHash(job: object): string;
|
|
|
99
99
|
* share a workflow key iff they ran the same goal, checks, guardrails and close — whatever source they ran on, wherever they wrote, whatever caps they had.
|
|
100
100
|
* It is NOT a signature: {@link jobSpecHash} (which covers the caps and the fence) stays what the person signs, and
|
|
101
101
|
* a reuse lands on a NEW jobSpecHash with the SAME workflowKey. Same never-throws contract as `jobSpecHash`, and
|
|
102
|
-
* the same resolved-`tools` form, so an omitted-`tools` spec and its spelled-out menu share a key.
|
|
102
|
+
* the same resolved-`tools` form, so an omitted-`tools` spec and its spelled-out menu share a key. A soft-green spec keys on its
|
|
103
|
+
* RESOLVED judge identity (an absent `judge` is its worker's), so pinning the default judge never changes the key.
|
|
103
104
|
* @param {object} job
|
|
104
105
|
* @returns {string} sha256 hex
|
|
105
106
|
*/
|
|
@@ -277,6 +278,12 @@ export const CONDITION_KEYS: readonly string[];
|
|
|
277
278
|
* reuse (so what the key ignores is exactly what the person may edit, never two spellings).
|
|
278
279
|
*/
|
|
279
280
|
export const REUSE_OPEN_SPEC_FIELDS: readonly string[];
|
|
281
|
+
/**
|
|
282
|
+
* The signed spec's schedule fields: {@link workflowKey} ignores them too, so a scheduled spec keeps the workflow
|
|
283
|
+
* key of the green run it was scheduled from (else Reuse would refuse every scheduled spec). They stay inside
|
|
284
|
+
* {@link jobSpecHash}. Kept apart from {@link REUSE_OPEN_SPEC_FIELDS}, which names the Reuse boxes.
|
|
285
|
+
*/
|
|
286
|
+
export const SCHEDULE_SPEC_FIELDS: readonly string[];
|
|
280
287
|
/**
|
|
281
288
|
* The worker-identity fields {@link workflowKey} ALSO ignores (hamr 2026-10-04: Model is open on a reuse; the Name
|
|
282
289
|
* chosen in Settings carries its provider and baseUrl with it). They stay inside {@link jobSpecHash}, so what the person
|
package/types/kinds.d.ts
CHANGED
|
@@ -645,6 +645,11 @@ export type Ctx = {
|
|
|
645
645
|
timeoutMs?: number;
|
|
646
646
|
deadlineMs?: number;
|
|
647
647
|
};
|
|
648
|
+
onRubricEvidence?: (e: {
|
|
649
|
+
step: number;
|
|
650
|
+
evidence: any[];
|
|
651
|
+
evidenceTotal?: number;
|
|
652
|
+
}) => void;
|
|
648
653
|
onStage?: (row: {
|
|
649
654
|
stage: string | null;
|
|
650
655
|
kind: string | null;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** @param {Dropped} d @returns {string} the plain sentence for one drop */
|
|
2
|
+
export function dropSentence(d: Dropped): string;
|
|
3
|
+
/**
|
|
4
|
+
* One row per fact that lost something: the sentences (one per dropped word, then the fact's own), and whether the whole fact went.
|
|
5
|
+
* @param {Dropped[]|undefined|null} dropped
|
|
6
|
+
* @returns {{line: number, rule?: number, fact: string, full: boolean, sentences: string[]}[]}
|
|
7
|
+
*/
|
|
8
|
+
export function dropRows(dropped: Dropped[] | undefined | null): {
|
|
9
|
+
line: number;
|
|
10
|
+
rule?: number;
|
|
11
|
+
fact: string;
|
|
12
|
+
full: boolean;
|
|
13
|
+
sentences: string[];
|
|
14
|
+
}[];
|
|
15
|
+
/**
|
|
16
|
+
* A row as one Not-checked line, in the person's own words: `line N: "<the ~ rule as written, or the fact's name>" — <sentences>`.
|
|
17
|
+
* @param {{line: number, rule?: number, fact: string, sentences: string[]}} row @param {any[]|null|undefined} jobLines @param {(l: any) => string[]} rulesOf
|
|
18
|
+
* @returns {string}
|
|
19
|
+
*/
|
|
20
|
+
export function dropLine(row: {
|
|
21
|
+
line: number;
|
|
22
|
+
rule?: number;
|
|
23
|
+
fact: string;
|
|
24
|
+
sentences: string[];
|
|
25
|
+
}, jobLines: any[] | null | undefined, rulesOf: (l: any) => string[]): string;
|
|
26
|
+
export type Dropped = import("./pagerules.js").Dropped;
|