bareloop 0.23.0 → 0.25.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 +218 -0
- package/bareloop.context.md +233 -19
- package/package.json +1 -1
- package/src/authorflow.js +17 -7
- package/src/authoring.js +32 -0
- package/src/authorjob.js +108 -36
- package/src/calibrate.js +33 -12
- package/src/cardauthor.js +23 -16
- package/src/cli.js +36 -5
- package/src/declaredclose.js +17 -10
- package/src/index.js +17 -5
- package/src/job.js +58 -3
- package/src/judged.js +132 -14
- package/src/kinds.js +84 -13
- package/src/planrun.js +14 -2
- package/src/providers.js +143 -18
- package/src/run.js +9 -4
- package/src/source.js +849 -0
- package/src/validate.js +19 -0
- package/types/authoring.d.ts +30 -0
- package/types/authorjob.d.ts +10 -6
- package/types/calibrate.d.ts +9 -2
- package/types/cardauthor.d.ts +13 -11
- package/types/cli.d.ts +2 -1
- package/types/declaredclose.d.ts +2 -0
- package/types/index.d.ts +2 -1
- package/types/job.d.ts +22 -1
- package/types/judged.d.ts +123 -14
- package/types/kinds.d.ts +66 -3
- package/types/planrun.d.ts +10 -2
- package/types/providers.d.ts +73 -11
- package/types/run.d.ts +9 -3
- package/types/source.d.ts +206 -0
- package/types/validate.d.ts +7 -0
package/src/validate.js
CHANGED
|
@@ -147,9 +147,28 @@ export const SECRET_PATTERNS = [
|
|
|
147
147
|
/(?<![A-Za-z0-9_-])github_pat_[A-Za-z0-9_]{20,}/,
|
|
148
148
|
/(?<![A-Za-z0-9_-])AKIA[0-9A-Z]{16}/,
|
|
149
149
|
/(?<![A-Za-z0-9_-])xox[bap]-[A-Za-z0-9-]{10,}/,
|
|
150
|
+
// Google/Gemini API key: `AIza` + 35 chars of [0-9A-Za-z_-] (39 total, fixed
|
|
151
|
+
// length by Google's own issuance format). Admitted with the gemini-api
|
|
152
|
+
// provider (PRD item 31.3, F160) — was missing on this branch until then.
|
|
153
|
+
/(?<![A-Za-z0-9_-])AIza[0-9A-Za-z_-]{35}/,
|
|
150
154
|
];
|
|
151
155
|
const SECRET_RE = new RegExp(SECRET_PATTERNS.map((r) => r.source).join('|'));
|
|
152
156
|
|
|
157
|
+
/** Human-readable name for each entry in `SECRET_PATTERNS`, SAME order, SAME
|
|
158
|
+
* length — for a caller that must name WHICH shape matched (a refusal
|
|
159
|
+
* message, an audit line) without ever printing the matched text itself. Kept
|
|
160
|
+
* beside the inventory it describes rather than hand-typed at each call site,
|
|
161
|
+
* for the same reason `scanSecrets`/`redactSecrets` are: a second, drifting
|
|
162
|
+
* copy is how a name and its pattern come apart. */
|
|
163
|
+
export const SECRET_PATTERN_NAMES = [
|
|
164
|
+
'sk- prefixed API key',
|
|
165
|
+
'GitHub personal access token (ghp_)',
|
|
166
|
+
'GitHub fine-grained PAT (github_pat_)',
|
|
167
|
+
'AWS access key ID (AKIA)',
|
|
168
|
+
'Slack token (xox)',
|
|
169
|
+
'Google/Gemini API key (AIza)',
|
|
170
|
+
];
|
|
171
|
+
|
|
153
172
|
/**
|
|
154
173
|
* Scan a RAW text stream (a spine file, a close's output, a transcript) for
|
|
155
174
|
* known secret shapes and return the literal matches. The ONE spelling of the
|
package/types/authoring.d.ts
CHANGED
|
@@ -328,6 +328,36 @@ export const VERDICT_CLASSES: readonly string[];
|
|
|
328
328
|
export const LOCKED_CLASSES: readonly string[];
|
|
329
329
|
/** the classes v1 actually builds */
|
|
330
330
|
export const LIVE_CLASSES: readonly string[];
|
|
331
|
+
/** OFF THE MENU, but still built — a THIRD state, distinct from both lists above
|
|
332
|
+
* (PRD item 31.1, hamr 2026-09-09: *"retire hitl from list, keep its code"*, and
|
|
333
|
+
* *"if it's not on menu, you can't reach it, from menu"*).
|
|
334
|
+
*
|
|
335
|
+
* `hitl` was retired by ruling at v1.71 and the class moved to fwdloop (PRD item
|
|
336
|
+
* 29), but no constant was ever updated, so `runInterview` still returned
|
|
337
|
+
* `ok:true` for a hitl pick — an authorable job for a class this product no
|
|
338
|
+
* longer closes.
|
|
339
|
+
*
|
|
340
|
+
* Why this is NOT `LOCKED_CLASSES`. Locked means INEXPRESSIBLE: no guard battery
|
|
341
|
+
* exists, so `validateCloseDecl` cannot check the close and must refuse
|
|
342
|
+
* (`src/declaredclose.js:306`). hitl's battery, question set, composition rule and
|
|
343
|
+
* runtime all exist and are tested — locking it would make every one of them
|
|
344
|
+
* unreachable, which is not "keeping the code", it is abandoning it in place with
|
|
345
|
+
* its tests deleted. So the split is:
|
|
346
|
+
*
|
|
347
|
+
* LOCKED_CLASSES — no battery. Cannot be validated, cannot run. (empty today)
|
|
348
|
+
* UNLISTED_CLASSES — battery exists, validates and RUNS. Just never OFFERED.
|
|
349
|
+
* LIVE_CLASSES — everything the system can validate and run (locked removed).
|
|
350
|
+
*
|
|
351
|
+
* Read by the AUTHORING surface only (`runInterview`, `authorClose`'s precheck).
|
|
352
|
+
* The spec validator, the close validator and the runtime deliberately do NOT
|
|
353
|
+
* read it: a hitl spec that already exists still validates and still runs, which
|
|
354
|
+
* is what keeps the code alive and under test. Nothing can AUTHOR a new one.
|
|
355
|
+
* @type {readonly string[]} */
|
|
356
|
+
export const UNLISTED_CLASSES: readonly string[];
|
|
357
|
+
/** what the authoring interview actually OFFERS: live, minus unlisted. This is
|
|
358
|
+
* "the menu" in hamr's sentence, and it is the only list an authoring refusal
|
|
359
|
+
* should ever name. */
|
|
360
|
+
export const MENU_CLASSES: readonly string[];
|
|
331
361
|
/**
|
|
332
362
|
* The whole vocabulary, as DATA. `shape` and `asserts` are the strings the
|
|
333
363
|
* authoring prompt renders (M3) — the prompt and this validator must judge the
|
package/types/authorjob.d.ts
CHANGED
|
@@ -81,7 +81,7 @@ 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, ceilingUsd?: number|null,
|
|
84
|
+
* seedRef?: string|null, scout?: any, listing?: any, ceilingUsd?: number|null, judgeModel?: string|null,
|
|
85
85
|
* onPhase?: (phase: string, data?: any) => void,
|
|
86
86
|
* onCall?: (call: {label: string, costUsd: number|null, unpricedRounds: number}) => void,
|
|
87
87
|
* seedFn?: Function, scoutFn?: Function, listingFn?: Function,
|
|
@@ -91,7 +91,7 @@ export function refuseLockedKind(kind: string): Refusal;
|
|
|
91
91
|
* closeDecl: any, seedRef: string|null, authoring: any, judged: any, reds: Red[],
|
|
92
92
|
* stop: string|null, cost: any, interview: any}>}
|
|
93
93
|
*/
|
|
94
|
-
export function authorCloseForJob({ answers, repoPath, lang, verdictType, questions, generate, provider, seedRef, scout, listing, ceilingUsd, onPhase, onCall, seedFn, scoutFn, listingFn, authorFn, authorOpts, signerFix, proposeFn, compileOpts, }: {
|
|
94
|
+
export function authorCloseForJob({ answers, repoPath, lang, verdictType, questions, generate, provider, seedRef, scout, listing, ceilingUsd, judgeModel, onPhase, onCall, seedFn, scoutFn, listingFn, authorFn, authorOpts, signerFix, proposeFn, compileOpts, }: {
|
|
95
95
|
answers: Record<string | number, any>;
|
|
96
96
|
repoPath?: string | null;
|
|
97
97
|
lang: string;
|
|
@@ -103,6 +103,7 @@ export function authorCloseForJob({ answers, repoPath, lang, verdictType, questi
|
|
|
103
103
|
scout?: any;
|
|
104
104
|
listing?: any;
|
|
105
105
|
ceilingUsd?: number | null;
|
|
106
|
+
judgeModel?: string | null;
|
|
106
107
|
onPhase?: (phase: string, data?: any) => void;
|
|
107
108
|
onCall?: (call: {
|
|
108
109
|
label: string;
|
|
@@ -207,12 +208,12 @@ export function assembleSpec(specDraft: any, { closeDecl, verdictType }: {
|
|
|
207
208
|
*
|
|
208
209
|
* @param {{spec: any, workdir: string, seedRef?: string|null, shellCapUsd?: number,
|
|
209
210
|
* timeoutMs?: number, seedFn?: Function, listingFn?: Function, seedReadFn?: Function,
|
|
210
|
-
* judgeLoop?: Function|null, onJudgeCost?: ((c: any) => void)|null,
|
|
211
|
-
* ceilingUsd?: number|null, priorCalls?: any[]}} o
|
|
211
|
+
* judgeLoop?: Function|null, judgeModel?: string|null, onJudgeCost?: ((c: any) => void)|null,
|
|
212
|
+
* calibrateFn?: Function, ceilingUsd?: number|null, priorCalls?: any[]}} o
|
|
212
213
|
* @returns {Promise<{ok: boolean, specHash: string|null, seedRef: string|null,
|
|
213
214
|
* gates: any, work: any[], guards: any[], stops: any[], reds: Red[], refusal: Refusal|null}>}
|
|
214
215
|
*/
|
|
215
|
-
export function prepareSigning({ spec, workdir, seedRef, shellCapUsd, timeoutMs, seedFn, listingFn, seedReadFn, judgeLoop, onJudgeCost, calibrateFn, ceilingUsd, priorCalls, }: {
|
|
216
|
+
export function prepareSigning({ spec, workdir, seedRef, shellCapUsd, timeoutMs, seedFn, listingFn, seedReadFn, judgeLoop, judgeModel, onJudgeCost, calibrateFn, ceilingUsd, priorCalls, }: {
|
|
216
217
|
spec: any;
|
|
217
218
|
workdir: string;
|
|
218
219
|
seedRef?: string | null;
|
|
@@ -222,6 +223,7 @@ export function prepareSigning({ spec, workdir, seedRef, shellCapUsd, timeoutMs,
|
|
|
222
223
|
listingFn?: Function;
|
|
223
224
|
seedReadFn?: Function;
|
|
224
225
|
judgeLoop?: Function | null;
|
|
226
|
+
judgeModel?: string | null;
|
|
225
227
|
onJudgeCost?: ((c: any) => void) | null;
|
|
226
228
|
calibrateFn?: Function;
|
|
227
229
|
ceilingUsd?: number | null;
|
|
@@ -277,4 +279,6 @@ import { requiredAnswersFor } from './authorflow.js';
|
|
|
277
279
|
import { VERDICT_CLASSES } from './authoring.js';
|
|
278
280
|
import { LOCKED_CLASSES } from './authoring.js';
|
|
279
281
|
import { LIVE_CLASSES } from './authoring.js';
|
|
280
|
-
|
|
282
|
+
import { UNLISTED_CLASSES } from './authoring.js';
|
|
283
|
+
import { MENU_CLASSES } from './authoring.js';
|
|
284
|
+
export { QUESTION_SETS, questionsFor, requiredAnswersFor, VERDICT_CLASSES, LOCKED_CLASSES, LIVE_CLASSES, UNLISTED_CLASSES, MENU_CLASSES };
|
package/types/calibrate.d.ts
CHANGED
|
@@ -80,7 +80,13 @@ export function factsResist(facts: any, gold: any, artifactText: string): {
|
|
|
80
80
|
* graded one: `ok` is false, the cases nobody bought are absent rather than recorded
|
|
81
81
|
* as failures, and `casualty` stays null — the transport was fine, the operator's own
|
|
82
82
|
* governance stopped the gate.
|
|
83
|
-
*
|
|
83
|
+
* `judgeModel` is REQUIRED and has no default (PRD item 32.1). It is the identity
|
|
84
|
+
* the caller resolved (`resolveJudge`, src/judged.js) and it is what the graded set
|
|
85
|
+
* is STAMPED with — `setHash` folds it in, so a set certified by one judge cannot be
|
|
86
|
+
* mistaken for the same set certified by another. A default here would be the silent
|
|
87
|
+
* fall-back the whole judge-identity change exists to remove: a gate that grades
|
|
88
|
+
* under a model nobody named certifies a floor nobody can attribute.
|
|
89
|
+
* @param {{cases: any, card: any, judgeLoop: Function|null, judgeModel: string,
|
|
84
90
|
* onCost?: (c: any) => void, attempts?: number, battery?: any[], batteryCard?: any,
|
|
85
91
|
* capStop?: () => 'cap-halt'|'pricing-red'|null}} o
|
|
86
92
|
* @returns {Promise<{ok: boolean, stop: string|null, casualty: any,
|
|
@@ -90,10 +96,11 @@ export function factsResist(facts: any, gold: any, artifactText: string): {
|
|
|
90
96
|
* cardHash: string|null, casesHash: string|null, setHash: string|null,
|
|
91
97
|
* costUsd: number|null, knownUsd: number, spendComplete: boolean, calls: any[]}>}
|
|
92
98
|
*/
|
|
93
|
-
export function runCalibration({ cases, card, judgeLoop, onCost, attempts, battery, batteryCard, capStop, }: {
|
|
99
|
+
export function runCalibration({ cases, card, judgeLoop, judgeModel, onCost, attempts, battery, batteryCard, capStop, }: {
|
|
94
100
|
cases: any;
|
|
95
101
|
card: any;
|
|
96
102
|
judgeLoop: Function | null;
|
|
103
|
+
judgeModel: string;
|
|
97
104
|
onCost?: (c: any) => void;
|
|
98
105
|
attempts?: number;
|
|
99
106
|
battery?: any[];
|
package/types/cardauthor.d.ts
CHANGED
|
@@ -261,15 +261,16 @@ export function signJudgedArtifacts({ proposal, fix }: {
|
|
|
261
261
|
* - THE CASES land beside the stages as `calibration.cases` — a close-level
|
|
262
262
|
* artifact, because the set calibrates the RULER and not one stage's params,
|
|
263
263
|
* and because module 5's gate reads it before any stage runs.
|
|
264
|
-
* - THE JUDGE MODEL lands beside them as `calibration.judgeModel
|
|
265
|
-
*
|
|
266
|
-
*
|
|
267
|
-
*
|
|
268
|
-
* the set has to carry which
|
|
269
|
-
* signed floor from a
|
|
270
|
-
* a
|
|
271
|
-
* re-sign is a re-run of the calibration gate.
|
|
272
|
-
*
|
|
264
|
+
* - THE JUDGE MODEL lands beside them as `calibration.judgeModel`. Since PRD item
|
|
265
|
+
* 32.1 that is the RESOLVED judge identity the caller hands in (`resolveJudge`,
|
|
266
|
+
* src/judged.js — the spec's signed `judge` override, else the job's own worker
|
|
267
|
+
* model), not a library pin. A calibration set is only worth the judge that
|
|
268
|
+
* graded it, so the set has to carry which judge certified it or nothing
|
|
269
|
+
* downstream can tell a signed floor from a moved one. Storing it HERE, inside
|
|
270
|
+
* the spec, is what makes a judge change flip `jobSpecHash`: the signature dies,
|
|
271
|
+
* the signer re-signs, and a re-sign is a re-run of the calibration gate. It is
|
|
272
|
+
* REQUIRED, with no default — a set stamped with a model nobody named is exactly
|
|
273
|
+
* the unattributable floor this field exists to prevent (F45).
|
|
273
274
|
*
|
|
274
275
|
* A card with NOWHERE TO LAND THROWS. It is a caller's own broken input — a
|
|
275
276
|
* signed rubric folded into a close with no judged ruler — and there is no safe
|
|
@@ -278,12 +279,13 @@ export function signJudgedArtifacts({ proposal, fix }: {
|
|
|
278
279
|
* The input is never mutated: a closeDecl is a signed artefact and rewriting a
|
|
279
280
|
* caller's copy in place is how two readers come to disagree about what was
|
|
280
281
|
* signed.
|
|
281
|
-
* @param {any} closeDecl @param {{card: any, cases: any[]}} o
|
|
282
|
+
* @param {any} closeDecl @param {{card: any, cases: any[], judgeModel: string}} o
|
|
282
283
|
* @returns {any} a new closeDecl
|
|
283
284
|
*/
|
|
284
|
-
export function foldJudgedArtifacts(closeDecl: any, { card, cases }: {
|
|
285
|
+
export function foldJudgedArtifacts(closeDecl: any, { card, cases, judgeModel }: {
|
|
285
286
|
card: any;
|
|
286
287
|
cases: any[];
|
|
288
|
+
judgeModel: string;
|
|
287
289
|
}): any;
|
|
288
290
|
/**
|
|
289
291
|
* ONE compile call: the person's Q6 and Q7 in, a proposal out.
|
package/types/cli.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* code, so `bin/bareloop.mjs` can set `process.exitCode` and let node flush
|
|
4
4
|
* queued stdout on its own (F-something: `process.exit()` can discard it).
|
|
5
5
|
* @param {string[]} argv
|
|
6
|
-
* @param {{ env?: Record<string,string|undefined>, stdout?: any, stderr?: any, cwd?: string, provider?: any, providerFor?: any, judgeProvider?: any, now?: () => number, stdin?: any }} deps
|
|
6
|
+
* @param {{ env?: Record<string,string|undefined>, stdout?: any, stderr?: any, cwd?: string, provider?: any, providerFor?: any, judgeProvider?: any, judgeModel?: string|null, now?: () => number, stdin?: any }} deps
|
|
7
7
|
* @returns {Promise<number>}
|
|
8
8
|
*/
|
|
9
9
|
export function main(argv: string[], deps?: {
|
|
@@ -14,6 +14,7 @@ export function main(argv: string[], deps?: {
|
|
|
14
14
|
provider?: any;
|
|
15
15
|
providerFor?: any;
|
|
16
16
|
judgeProvider?: any;
|
|
17
|
+
judgeModel?: string | null;
|
|
17
18
|
now?: () => number;
|
|
18
19
|
stdin?: any;
|
|
19
20
|
}): Promise<number>;
|
package/types/declaredclose.d.ts
CHANGED
|
@@ -110,6 +110,7 @@ export function guardNames(closeDecl: any, verdictType: string): string[];
|
|
|
110
110
|
* seedTrees?: any, gapCap?: number, maxBuffer?: number, baselineMode?: 'auto'|'worktree',
|
|
111
111
|
* humanRuling?: {decision: string, text?: string|null}|null,
|
|
112
112
|
* judgeLoop?: ((o: {system: string}) => any)|null,
|
|
113
|
+
* judgeModel?: string|null,
|
|
113
114
|
* onJudgeCost?: ((c: any) => void)|null,
|
|
114
115
|
* callBounds?: (() => {timeoutMs?: number, deadlineMs?: number})|null}} [opts]
|
|
115
116
|
* @returns {Promise<any>}
|
|
@@ -129,6 +130,7 @@ export function runDeclaredStages(stages: any[], redact?: (s: string) => string,
|
|
|
129
130
|
judgeLoop?: ((o: {
|
|
130
131
|
system: string;
|
|
131
132
|
}) => any) | null;
|
|
133
|
+
judgeModel?: string | null;
|
|
132
134
|
onJudgeCost?: ((c: any) => void) | null;
|
|
133
135
|
callBounds?: (() => {
|
|
134
136
|
timeoutMs?: number;
|
package/types/index.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ export { workBranchName, prepareWorkBranch, WORK_BRANCH_PREFIX, WORK_BRANCH_RE }
|
|
|
15
15
|
export { createReadShim, wrapReadTool, readShimArm, readShimStrategy, READ_SHIM_CAP, READ_SHIM_STRATEGY, READ_SHIM_DIFF_STRATEGY, READ_SHIM_ARMS } from "./readshim.js";
|
|
16
16
|
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, JUDGED_FLOOR_KIND, normalizeHumanRuling, resolveHumanRuling, JUDGE_ATTEMPTS, MAX_JUDGED_PATHS, REVIEW_DOOR, DOOR_OPEN_OUTCOMES, REVIEW_DOOR_CLASSES, doorOpens, mechanicalStages } from "./kinds.js";
|
|
17
17
|
export { answerReviewDoor, doorRecordOf, doorAgeGate } from "./reviewdoor.js";
|
|
18
|
-
export { JUDGE_MODEL, JUDGE_MAX_TOKENS, JUDGE_RULES, JUDGE_RULE_IDS, LOCATE_AXES, LOCATE_LABEL, validateCard, validateFacts, locatePrompt, runLocate, decide, defaultJudgeLoop, CALIBRATION_SIZE, CASE_VERDICTS, validateCalibrationSet, validateJudgedArtifacts, expectedOf } from "./judged.js";
|
|
18
|
+
export { JUDGE_MODEL, resolveJudge, JUDGE_MAX_TOKENS, JUDGE_RULES, JUDGE_RULE_IDS, LOCATE_AXES, LOCATE_LABEL, validateCard, validateFacts, locatePrompt, runLocate, decide, defaultJudgeLoop, CALIBRATION_SIZE, CASE_VERDICTS, validateCalibrationSet, validateJudgedArtifacts, expectedOf } from "./judged.js";
|
|
19
19
|
export { proposeJudgedArtifacts, signJudgedArtifacts, foldJudgedArtifacts, proposalSchema, proposalTool, cardCasesPrompt, PROPOSAL_TOOL_NAME, PROPOSAL_LABEL, MAX_PROPOSAL_RETRIES, COMPILE_SYSTEM } from "./cardauthor.js";
|
|
20
20
|
export { runCalibration, compareExpectation, factsResist, artifactHash, INJECTION_LOCATE_BATTERY, INJECTION_CARD, CALIBRATION_LABEL, CASUALTY_AXES } from "./calibrate.js";
|
|
21
21
|
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, classMenu, closeCeiling, NEVER_OFFERED_KINDS } from "./authoring.js";
|
|
@@ -29,3 +29,4 @@ export { runInterview, authorCloseForJob, assembleSpec, prepareSigning, refusalE
|
|
|
29
29
|
export { PROMPT_REGISTERS, isPromptFile } from "./promptregisters.js";
|
|
30
30
|
export { exportBundle, bundleHash, readBundle, resolveBundleSpec, checkEnvelope, bless, verifyBlessing, appendHistory, checkBundleDeps } from "./bundle.js";
|
|
31
31
|
export { readCloseScripts, checkCloseAbsolutePaths, absolutePathLiteralsOf, hashCloseScriptBytes, checkCloseByteSignature, checkStageByteSignature, signCloseScripts } from "./close-integrity.js";
|
|
32
|
+
export { prepareSource, proveDestination, copyOut, readSourceManifest, frontDoorFromManifest } from "./source.js";
|
package/types/job.d.ts
CHANGED
|
@@ -210,7 +210,28 @@ export const CADENCE_UNITS: readonly string[];
|
|
|
210
210
|
/** PRD item 28 (2026-09-06/09-09): `openai-api` — an OpenAI-shaped provider,
|
|
211
211
|
* constructed via `src/providers.js`'s factory. hamr's ruling (PRD 30.7):
|
|
212
212
|
* `deepseek-chat` is THE secondary provider (one, not a menu of half-tested
|
|
213
|
-
* models); the factory's tier table is where that lives, not this menu.
|
|
213
|
+
* models); the factory's tier table is where that lives, not this menu.
|
|
214
|
+
*
|
|
215
|
+
* PRD item 31.3 (hamr, 2026-09-09: *"anthropic, openai, gemini drop ollama for
|
|
216
|
+
* now"*): `gemini-api` joins. That is bareloop matching bare-agent's own
|
|
217
|
+
* adapter surface rather than curating a shorter list — bare-agent exports four
|
|
218
|
+
* real HTTP backends (Anthropic, OpenAI, Gemini, Ollama) plus CLIPipe and the
|
|
219
|
+
* FallbackProvider composite; `provider-http.js`, `provider-stop-reason.js`,
|
|
220
|
+
* `provider-temperature.js` and `provider-usage.js` are shared HELPERS, not
|
|
221
|
+
* backends, and were miscounted as providers once — the export list, never the
|
|
222
|
+
* filenames, is the source of truth.
|
|
223
|
+
*
|
|
224
|
+
* Ollama is deliberately NOT here. Beyond hamr's word, it is the one entry
|
|
225
|
+
* whose economics differ in kind: it takes no API key and bills nothing, so
|
|
226
|
+
* every round would price at $0 through machinery that treats $0 as a real
|
|
227
|
+
* price. An unpriced round reported as free is the exact honesty violation the
|
|
228
|
+
* `?? 0` rule exists to stop, and admitting it needs that question answered
|
|
229
|
+
* first, not a menu entry.
|
|
230
|
+
*
|
|
231
|
+
* `gemini-api` is ADMITTED-PENDING-PROBE: the probe rule stands (item 28
|
|
232
|
+
* ruling (d)) and gemini has zero runs. See `PROBE_STATUS` in
|
|
233
|
+
* `src/providers.js` — a spec may name it, and the runner says out loud that
|
|
234
|
+
* nothing has proven it. */
|
|
214
235
|
export const PROVIDERS: readonly string[];
|
|
215
236
|
/** V3 environment label: declared keys only — every field is a lineage-key
|
|
216
237
|
* candidate at N3. `provider` is part of the key by definition (top-level,
|
package/types/judged.d.ts
CHANGED
|
@@ -1,3 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RESOLVE WHICH MODEL GRADES THIS JOB (PRD item 32.1).
|
|
3
|
+
*
|
|
4
|
+
* hamr, 2026-09-10: *"what i care about is that judge becomes llm agnostic and
|
|
5
|
+
* not set to one model or provider"* — and the shape he named: *"defaults to
|
|
6
|
+
* whatever llm is used and can be overriden"*.
|
|
7
|
+
*
|
|
8
|
+
* So, in precedence order:
|
|
9
|
+
* 1. `spec.judge` — an explicit, SIGNED `{provider, model}`. This is how a run
|
|
10
|
+
* pins a judge deliberately different from its worker (an independent
|
|
11
|
+
* reader, or a judge whose calibration a job wants to keep while the worker
|
|
12
|
+
* moves). It is a spec field the HUMAN signs, part of `jobSpecHash` like
|
|
13
|
+
* every other; the drafting agent cannot express it, because naming your
|
|
14
|
+
* own examiner is arbiter territory.
|
|
15
|
+
* 2. otherwise the job's OWN worker provider and model. A DeepSeek job judges
|
|
16
|
+
* on DeepSeek and needs no second account — which is the whole point: after
|
|
17
|
+
* item 31.4 a green job runs on its own key alone, and this is what lets a
|
|
18
|
+
* JUDGED one do the same.
|
|
19
|
+
*
|
|
20
|
+
* There is deliberately NO third fallback to `JUDGE_MODEL`. A caller that cannot
|
|
21
|
+
* say which model will grade has not wired a judge, and the grading path stops
|
|
22
|
+
* as a wiring gap rather than grading under an identity nobody chose — the same
|
|
23
|
+
* answer an absent `judgeLoop` already gets. A silent default here would be the
|
|
24
|
+
* exact silent-ignore class that `endpointKey` and F149 exist to prevent, except
|
|
25
|
+
* pointed at the arbiter.
|
|
26
|
+
*
|
|
27
|
+
* SELF-GRADING is licensed by measurement, not by this function: the judge
|
|
28
|
+
* renders no verdict (it locates facts; `decide()` is deterministic), and the
|
|
29
|
+
* calibration gate — 10 cases, a 10-of-10 floor, no partial credit, cases that
|
|
30
|
+
* MUST fail — is exactly the instrument that catches a judge which cannot see
|
|
31
|
+
* failures. If a worker-family judge cannot pass its own calibration, that is
|
|
32
|
+
* the finding, and the gate refuses to sign.
|
|
33
|
+
*
|
|
34
|
+
* @param {{specJudge?: any, workerProvider?: string, workerModel?: string}} o
|
|
35
|
+
* @returns {{provider: string, model: string}}
|
|
36
|
+
*/
|
|
37
|
+
export function resolveJudge({ specJudge, workerProvider, workerModel }?: {
|
|
38
|
+
specJudge?: any;
|
|
39
|
+
workerProvider?: string;
|
|
40
|
+
workerModel?: string;
|
|
41
|
+
}): {
|
|
42
|
+
provider: string;
|
|
43
|
+
model: string;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* `resolveJudge` needs a worker MODEL already resolved, and an authoring
|
|
47
|
+
* pipeline has to compute one identity at TWO different moments — once at
|
|
48
|
+
* compose time, to STAMP `closeDecl.calibration.judgeModel` into the spec it
|
|
49
|
+
* is about to sign, and again at the calibration gate that grades against
|
|
50
|
+
* that stamp — from a value that is not yet a validated spec (the operator's
|
|
51
|
+
* draft) the first time and is one (the assembled spec) the second. Two
|
|
52
|
+
* hand-spelled compositions of `resolveWorkerModel` + `resolveJudge` is
|
|
53
|
+
* exactly the kind of pair that drifts (PRD F45's "a rule with no detector is
|
|
54
|
+
* prose" applies to a rule spelled TWICE just as much as to one spelled
|
|
55
|
+
* nowhere) — this is the one spelling both calls make, and it mirrors the
|
|
56
|
+
* SAME composition `scripts/run-u.mjs` applies at launch time: the named
|
|
57
|
+
* provider's own `tiers.sonnet` defaults an absent model, and a signed
|
|
58
|
+
* `judge` override wins over the worker default.
|
|
59
|
+
*
|
|
60
|
+
* `source` is read for `provider`/`model`/`judge` only, so a draft and the
|
|
61
|
+
* spec `assembleSpec` folds it into resolve identically — `assembleSpec`
|
|
62
|
+
* spreads the draft into the spec untouched on those three fields — and any
|
|
63
|
+
* draft that goes on to validate and sign therefore stamps and grades under
|
|
64
|
+
* the exact same identity `scripts/run-u.mjs` will resolve at run time.
|
|
65
|
+
*
|
|
66
|
+
* `source.provider` absent, or unresolvable, or `source.judge` malformed all
|
|
67
|
+
* THROW here exactly as `resolveProvider`/`resolveJudge` already do on their
|
|
68
|
+
* own — a caller composing this from a pre-validation draft is expected to
|
|
69
|
+
* catch that and use a placeholder, because a draft that cannot resolve here
|
|
70
|
+
* is a draft `validateJob` reds a few lines later regardless, before anything
|
|
71
|
+
* gets signed under the placeholder.
|
|
72
|
+
*
|
|
73
|
+
* `resolveWorkerModelFn` is taken as a PARAMETER rather than imported — this
|
|
74
|
+
* module cannot import `./job.js` directly: `job.js` imports
|
|
75
|
+
* `./declaredclose.js`, which imports `resolveJudge` from THIS module, and a
|
|
76
|
+
* `judged.js` → `job.js` edge would close that into a cycle. `resolveProvider`
|
|
77
|
+
* has no such conflict (`./providers.js` imports nothing local) and is
|
|
78
|
+
* imported directly.
|
|
79
|
+
*
|
|
80
|
+
* @param {{provider?: string, model?: string, judge?: any}} source draft or spec
|
|
81
|
+
* @param {string} fallbackProviderName used only when `source.provider` is absent
|
|
82
|
+
* @param {(o: {specModel?: string, flagModel?: string, defaultModel: string}) => {model: string, source: string}} resolveWorkerModelFn `resolveWorkerModel` from `./job.js`
|
|
83
|
+
* @returns {{provider: string, model: string}}
|
|
84
|
+
*/
|
|
85
|
+
export function resolveJobJudge(source: {
|
|
86
|
+
provider?: string;
|
|
87
|
+
model?: string;
|
|
88
|
+
judge?: any;
|
|
89
|
+
}, fallbackProviderName: string, resolveWorkerModelFn: (o: {
|
|
90
|
+
specModel?: string;
|
|
91
|
+
flagModel?: string;
|
|
92
|
+
defaultModel: string;
|
|
93
|
+
}) => {
|
|
94
|
+
model: string;
|
|
95
|
+
source: string;
|
|
96
|
+
}): {
|
|
97
|
+
provider: string;
|
|
98
|
+
model: string;
|
|
99
|
+
};
|
|
1
100
|
/**
|
|
2
101
|
* The rubric card: Q6's answer compiled into enumerated items, signed by the
|
|
3
102
|
* person and enumerated in the spec hash. `rule` selects from `JUDGE_RULES`;
|
|
@@ -201,25 +300,35 @@ export function decide(facts: any, card: any, { artifactText }?: {
|
|
|
201
300
|
reason: string | null;
|
|
202
301
|
};
|
|
203
302
|
/**
|
|
204
|
-
* THE JUDGE
|
|
205
|
-
* the
|
|
206
|
-
*
|
|
207
|
-
*
|
|
208
|
-
*
|
|
303
|
+
* THE JUDGE'S HISTORICAL PIN. Until PRD item 32 (2026-09-10) this constant WAS
|
|
304
|
+
* the judge: every grading path imported it, so bareloop could run a worker on
|
|
305
|
+
* any provider and still judge only on Claude.
|
|
306
|
+
*
|
|
307
|
+
* It is no longer read by any grading path. The judge identity is now RESOLVED
|
|
308
|
+
* per job (`resolveJudge` below) and travels as data — `ctx.judgeModel` into
|
|
309
|
+
* `runJudgedFloor`, an explicit argument into the calibration gate, and
|
|
310
|
+
* `closeDecl.calibration.judgeModel` into the signed spec, exactly as before.
|
|
311
|
+
* Keeping the export is deliberate: it is part of the public API
|
|
312
|
+
* (`src/index.js`) and an adopter importing it should not break on a minor.
|
|
313
|
+
* What it means now is "the judge bareloop pinned before item 32", which is
|
|
314
|
+
* still the right DEFAULT for an anthropic-api job and still the only tier with
|
|
315
|
+
* established injection resistance upstream (BA-20's `INJECTION_BATTERY` is
|
|
316
|
+
* haiku-4.5 only).
|
|
209
317
|
*
|
|
210
|
-
*
|
|
211
|
-
* rule with no
|
|
212
|
-
*
|
|
318
|
+
* THE ENFORCEMENT IS UNCHANGED, and still lives in three wired places because a
|
|
319
|
+
* rule with no detector is prose (F45) — only the value being compared moved
|
|
320
|
+
* from this constant to the resolved identity:
|
|
321
|
+
* 1. the identity is STORED with the set it graded — `foldJudgedArtifacts`
|
|
213
322
|
* writes it as `closeDecl.calibration.judgeModel`, inside the spec, so
|
|
214
|
-
* `jobSpecHash` covers it by construction.
|
|
323
|
+
* `jobSpecHash` covers it by construction. Change the judge and every
|
|
215
324
|
* signed judged spec hashes differently: the signature dies, and re-signing
|
|
216
325
|
* is what re-runs the calibration gate.
|
|
217
326
|
* 2. `validateCloseDecl` REQUIRES it on any stored set — a set nobody can
|
|
218
|
-
* attribute to a
|
|
219
|
-
* 3. `runJudgedFloor` refuses to grade when the stored
|
|
220
|
-
* naming both
|
|
221
|
-
* the new
|
|
222
|
-
* not on offer.
|
|
327
|
+
* attribute to a judge is a floor nobody can tell apart from a moved one.
|
|
328
|
+
* 3. `runJudgedFloor` refuses to grade when the stored identity is not the one
|
|
329
|
+
* about to grade, naming both. It does not degrade in either direction:
|
|
330
|
+
* grading on the new judge judges against a floor nobody calibrated, and
|
|
331
|
+
* the old judge is not on offer.
|
|
223
332
|
*/
|
|
224
333
|
export const JUDGE_MODEL: "claude-haiku-4-5";
|
|
225
334
|
/**
|
package/types/kinds.d.ts
CHANGED
|
@@ -1,3 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The judged stages of a close declaration, and whether it has any — the ONE
|
|
3
|
+
* spelling of "does this close ask a model to render anything?".
|
|
4
|
+
*
|
|
5
|
+
* The comment above `JUDGED_FLOOR_KIND` says five literals is how the readers
|
|
6
|
+
* come to disagree, and by PRD item 31.4 there were SIX open-coded
|
|
7
|
+
* `stages.filter(s => s.kind === JUDGED_FLOOR_KIND)` across the tree
|
|
8
|
+
* (`src/authorjob.js` twice, `src/cardauthor.js`, `src/declaredclose.js`,
|
|
9
|
+
* `scripts/run-author.mjs`, `scripts/author-readout.mjs`). 31.4 needed a
|
|
10
|
+
* seventh, in the runner, to decide whether a judge KEY is demanded — and a
|
|
11
|
+
* seventh spelling deciding a REFUSAL is the drift `scripts/run-u.mjs`'s own
|
|
12
|
+
* judge-provider comment warns about ("a second reading of the declaration
|
|
13
|
+
* that can drift from the one the runner actually executes"). So there is one
|
|
14
|
+
* reading now, and every caller shares it.
|
|
15
|
+
*
|
|
16
|
+
* Defensive on shape ON PURPOSE: callers pass raw specs read off disk and
|
|
17
|
+
* half-built drafts, not validated declarations. An absent/!object `closeDecl`
|
|
18
|
+
* or `stages` is "no judged stages", never a throw — the close VALIDATOR is
|
|
19
|
+
* what rejects a malformed declaration, and this predicate answering a
|
|
20
|
+
* question about one is not the place to re-litigate it.
|
|
21
|
+
* @param {any} closeDecl a close declaration (or anything, including undefined)
|
|
22
|
+
* @returns {any[]} the judged-floor stages, in declaration order
|
|
23
|
+
*/
|
|
24
|
+
export function judgedStages(closeDecl: any): any[];
|
|
25
|
+
/**
|
|
26
|
+
* Does this close declaration judge — i.e. will a judge model be CALLED?
|
|
27
|
+
* The question `scripts/run-u.mjs` asks before demanding a judge key (PRD item
|
|
28
|
+
* 31.4): a job that never judges must run on its own provider's key alone.
|
|
29
|
+
* @param {any} closeDecl
|
|
30
|
+
* @returns {boolean}
|
|
31
|
+
*/
|
|
32
|
+
export function closeJudges(closeDecl: any): boolean;
|
|
1
33
|
/**
|
|
2
34
|
* Does this run end at a review door? The operator's flag WINS in both
|
|
3
35
|
* directions and is never inferred: `true` opens it for any class, `false` shuts
|
|
@@ -17,6 +49,30 @@ export function doorOpens(job: any, reviewDoor?: boolean | null): boolean;
|
|
|
17
49
|
* @returns {any[]}
|
|
18
50
|
*/
|
|
19
51
|
export function mechanicalStages(stages: any[] | null | undefined): any[];
|
|
52
|
+
/**
|
|
53
|
+
* git, read-only, in a repository. Faults come back as `ok:false` with the
|
|
54
|
+
* stderr — a caller decides whether that is a stop.
|
|
55
|
+
*
|
|
56
|
+
* Exported (PRD item 33/M2, `src/source.js`) so the hidden-git seed a plain
|
|
57
|
+
* folder/file/URL job runs against goes through the SAME spawn primitive as
|
|
58
|
+
* every other git read in this file — a second `spawn('git', …)` for the
|
|
59
|
+
* source front door would be a second instrument with its own timeout and
|
|
60
|
+
* buffer ceiling to keep in sync with this one.
|
|
61
|
+
* @param {string} cwd @param {string[]} args
|
|
62
|
+
*/
|
|
63
|
+
export function git(cwd: string, args: string[]): Promise<{
|
|
64
|
+
ok: boolean;
|
|
65
|
+
out: string;
|
|
66
|
+
err: string;
|
|
67
|
+
code: null;
|
|
68
|
+
fault: string;
|
|
69
|
+
} | {
|
|
70
|
+
ok: boolean;
|
|
71
|
+
out: string;
|
|
72
|
+
err: string;
|
|
73
|
+
code: number;
|
|
74
|
+
fault: "failed";
|
|
75
|
+
}>;
|
|
20
76
|
/**
|
|
21
77
|
* D8's seed, READ rather than typed: HEAD at run start. A close stores the
|
|
22
78
|
* counting rule and never the number (D12), so which commit the run is measured
|
|
@@ -531,10 +587,16 @@ export type Red = {
|
|
|
531
587
|
* runner — never authored, never defaulted, and absent on every ordinary run.
|
|
532
588
|
* `judgeLoop` is the PAID seam the judged stage runs its locate call through, and
|
|
533
589
|
* it is operator territory for the same reason the worker's provider is: this
|
|
534
|
-
* module owns no provider and never picks one
|
|
535
|
-
*
|
|
536
|
-
* model — the stage stops as a wiring gap, the same answer `runPlan` gives a
|
|
590
|
+
* module owns no provider and never picks one. Absent is not a fall-back to some
|
|
591
|
+
* other model — the stage stops as a wiring gap, the same answer `runPlan` gives a
|
|
537
592
|
* native job with no native factory.
|
|
593
|
+
* `judgeModel` is the seam's other half (PRD item 32.1): WHICH model that loop
|
|
594
|
+
* drives, resolved by the runner (`resolveJudge`, src/judged.js — the spec's signed
|
|
595
|
+
* `judge` override, else the job's own worker model) rather than pinned in this
|
|
596
|
+
* library. It is required whenever `judgeLoop` is, and for the same reason: a
|
|
597
|
+
* verdict whose grader cannot be named is a floor nobody can attribute, and the
|
|
598
|
+
* signed calibration record has nothing to compare against. The two travel
|
|
599
|
+
* together or the stage stops.
|
|
538
600
|
* `onJudgeCost` is the METER, and it is the only reason a judged stage can be
|
|
539
601
|
* funded honestly: this executor cannot reach the run's ledger, so every locate
|
|
540
602
|
* call's cost is reported OUT through it, once per call, on every route including
|
|
@@ -566,6 +628,7 @@ export type Ctx = {
|
|
|
566
628
|
judgeLoop?: (o: {
|
|
567
629
|
system: string;
|
|
568
630
|
}) => any;
|
|
631
|
+
judgeModel?: string;
|
|
569
632
|
onJudgeCost?: (c: {
|
|
570
633
|
stage: string | null;
|
|
571
634
|
kind: string | null;
|
package/types/planrun.d.ts
CHANGED
|
@@ -196,8 +196,15 @@ export function planPrompt(job: any, scoutBlob: string, reds: any[] | null, maxS
|
|
|
196
196
|
* `false` → the drafter has no tools, so a native session would report NO cost — return a
|
|
197
197
|
* metered claude-json TEXT provider (`--output-format json`, `parse:'claude-json'`) instead,
|
|
198
198
|
* so its spend is never invisible. The Loop path (`anthropic-api`) never touches this.
|
|
199
|
+
* @param {string|null} [opts.judgeModel] softgreen — WHICH model that judge provider drives
|
|
200
|
+
* (PRD item 32.1). Resolved by the CALLER (`resolveJudge`, src/judged.js: the spec's signed
|
|
201
|
+
* `judge` override, else the job's own worker model), never pinned in this library. It
|
|
202
|
+
* travels with `judgeProvider` or the judged stage stops as a wiring gap: a verdict whose
|
|
203
|
+
* grader cannot be named is a floor nobody can attribute.
|
|
199
204
|
* @param {any} [opts.judgeProvider] softgreen — the provider a JUDGED close stage runs its
|
|
200
|
-
* locate call through,
|
|
205
|
+
* locate call through, built by the CALLER from the RESOLVED judge identity (PRD item
|
|
206
|
+
* 32.1: `resolveJudge`, src/judged.js — the spec's signed `judge` override, else the job's
|
|
207
|
+
* own worker provider and model), never pinned in this library. Separate
|
|
201
208
|
* from `provider`/`providerFor` on purpose: the judge tier is not a step knob and never
|
|
202
209
|
* agent-selectable, and the worker's binding is not a legal stand-in for it. Absent is not
|
|
203
210
|
* a fall-back — a judged stage with no seam instrument-STOPS as a wiring gap, the same
|
|
@@ -410,7 +417,7 @@ export function planPrompt(job: any, scoutBlob: string, reds: any[] | null, maxS
|
|
|
410
417
|
* 'branch-red' | 'cap-halt' | 'wall-halt' | 'provider-red' | 'interpreter-red' |
|
|
411
418
|
* 'step-stalled' | 'hitl-pause' | 'hitl-decision-red' | `step-red:<id>`
|
|
412
419
|
*/
|
|
413
|
-
export function runPlan(job: any, { workdir, provider, nativeProvider, providerFor, judgeProvider, emit, remainingUsd, isUnpriced, spendComplete, capRuns, strikeLimit, closeTimeoutMs, closeDir, maxStepRounds, layerRoot, readShim, scout, scoutRounds, bridge, now, priorWallMs, resumeSeed, resumeGrades, resumeReplans, resumeBranch, humanRuling, heldRuling, priorSpentUsd, reviewDoor, doorRerun, resumable }: {
|
|
420
|
+
export function runPlan(job: any, { workdir, provider, nativeProvider, providerFor, judgeProvider, judgeModel, emit, remainingUsd, isUnpriced, spendComplete, capRuns, strikeLimit, closeTimeoutMs, closeDir, maxStepRounds, layerRoot, readShim, scout, scoutRounds, bridge, now, priorWallMs, resumeSeed, resumeGrades, resumeReplans, resumeBranch, humanRuling, heldRuling, priorSpentUsd, reviewDoor, doorRerun, resumable }: {
|
|
414
421
|
workdir: string;
|
|
415
422
|
provider: any;
|
|
416
423
|
nativeProvider?: ((o: {
|
|
@@ -419,6 +426,7 @@ export function runPlan(job: any, { workdir, provider, nativeProvider, providerF
|
|
|
419
426
|
maxTurns: number;
|
|
420
427
|
hasTools: boolean;
|
|
421
428
|
}) => any) | undefined;
|
|
429
|
+
judgeModel?: string | null | undefined;
|
|
422
430
|
judgeProvider?: any;
|
|
423
431
|
emit: (type: string, data?: object) => object;
|
|
424
432
|
remainingUsd: () => number;
|