bareloop 0.39.0 → 0.41.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 +60 -0
- package/bareloop.context.md +137 -112
- package/package.json +2 -2
- package/src/authorflow.js +333 -58
- package/src/authoring.js +65 -2
- package/src/authorjob.js +57 -9
- package/src/authorreadout.js +50 -2
- package/src/authorrun.js +30 -27
- package/src/authorscout.js +9 -6
- package/src/bridges.js +1 -1
- package/src/bundle.js +7 -4
- package/src/bundlerun.js +4 -1
- package/src/calibrate.js +1 -1
- package/src/cardauthor.js +4 -1
- package/src/cli.js +1 -1
- package/src/config.js +129 -29
- package/src/declaredclose.js +4 -3
- package/src/draftspend.js +6 -1
- package/src/index.js +2 -4
- package/src/interviewrun.js +73 -52
- package/src/job.js +50 -11
- package/src/jobblock.js +140 -0
- package/src/judged.js +12 -44
- package/src/keysfile.js +15 -7
- package/src/kinds.js +2 -2
- package/src/ledger.js +1 -1
- package/src/modellist.js +84 -0
- package/src/monthly.js +23 -43
- package/src/panel/authorroutes.js +34 -19
- package/src/panel/authorsession.js +187 -72
- package/src/panel/index.html +699 -215
- package/src/panel/jobplan.js +107 -0
- package/src/panel/runroutes.js +3 -0
- package/src/panel/server.js +102 -28
- package/src/panel/settingsroutes.js +232 -173
- package/src/planrun.js +6 -6
- package/src/promptregisters.js +1 -1
- package/src/providerrows.js +226 -141
- package/src/providers.js +58 -250
- package/src/providershapes.js +18 -0
- package/src/replay.js +1 -1
- package/src/reuse.js +1 -1
- package/src/root.js +1 -1
- package/src/run.js +3 -3
- package/src/selection.js +1 -1
- package/src/source.js +64 -1
- package/src/text.js +13 -0
- package/src/thinking.js +130 -0
- package/src/transport.js +1 -1
- package/src/userrun.js +53 -76
- package/types/authorflow.d.ts +258 -39
- package/types/authoring.d.ts +7 -1
- package/types/authorjob.d.ts +35 -3
- package/types/authorreadout.d.ts +17 -1
- package/types/authorscout.d.ts +5 -3
- package/types/config.d.ts +23 -6
- package/types/declaredclose.d.ts +4 -1
- package/types/draftspend.d.ts +8 -2
- package/types/index.d.ts +1 -1
- package/types/job.d.ts +6 -6
- package/types/jobblock.d.ts +102 -0
- package/types/judged.d.ts +5 -36
- package/types/keysfile.d.ts +15 -4
- package/types/modellist.d.ts +50 -0
- package/types/monthly.d.ts +4 -3
- package/types/panel/authorsession.d.ts +44 -15
- package/types/panel/jobplan.d.ts +58 -0
- package/types/panel/server.d.ts +34 -4
- package/types/planrun.d.ts +1 -1
- package/types/providerrows.d.ts +192 -99
- package/types/providers.d.ts +35 -116
- package/types/providershapes.d.ts +10 -0
- package/types/run.d.ts +1 -1
- package/types/source.d.ts +26 -0
- package/types/thinking.d.ts +90 -0
- package/types/userrun.d.ts +6 -1
|
@@ -10,19 +10,36 @@ export function latestStep(steps: StepLine[], id: string): StepLine | undefined;
|
|
|
10
10
|
*/
|
|
11
11
|
export function advanceSteps(steps: StepLine[], id: string, detail?: string): void;
|
|
12
12
|
/**
|
|
13
|
-
* The confirm turn's plan as
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* @param {{
|
|
18
|
-
* @returns {string}
|
|
13
|
+
* The confirm turn's plan as a chat message (P7): a STRUCTURED `{role:'bot', kind:'plan', plan}` the page draws with the
|
|
14
|
+
* same renderer the Job tab uses — each numbered job line, its `~` rule, its drafted checks folded; the AI's own "not
|
|
15
|
+
* checked"; the always-on guards. `questions` (what the plan still asks) ride inside the plan. One owner of the shape.
|
|
16
|
+
* @param {{goal?: string, checks?: string[], checkItems?: {text: string, fromLine: number[]|null}[], notChecked?: string[], questions?: string[], protections?: string[]}} p the confirm turn's plan
|
|
17
|
+
* @param {{n: number, text: string, rule: string}[]|null} jobLines
|
|
18
|
+
* @returns {{role: 'bot', kind: 'plan', text: string, plan: ReturnType<typeof planFromConfirm> & {goal: string, questions: string[]}}}
|
|
19
19
|
*/
|
|
20
|
-
export function
|
|
20
|
+
export function planMessage(p: {
|
|
21
21
|
goal?: string;
|
|
22
22
|
checks?: string[];
|
|
23
|
+
checkItems?: {
|
|
24
|
+
text: string;
|
|
25
|
+
fromLine: number[] | null;
|
|
26
|
+
}[];
|
|
23
27
|
notChecked?: string[];
|
|
24
28
|
questions?: string[];
|
|
25
|
-
|
|
29
|
+
protections?: string[];
|
|
30
|
+
}, jobLines: {
|
|
31
|
+
n: number;
|
|
32
|
+
text: string;
|
|
33
|
+
rule: string;
|
|
34
|
+
}[] | null): {
|
|
35
|
+
role: "bot";
|
|
36
|
+
kind: "plan";
|
|
37
|
+
text: string;
|
|
38
|
+
plan: ReturnType<typeof planFromConfirm> & {
|
|
39
|
+
goal: string;
|
|
40
|
+
questions: string[];
|
|
41
|
+
};
|
|
42
|
+
};
|
|
26
43
|
/**
|
|
27
44
|
* `true` when `jobs/<name>.json` already exists in the repo's own jobs/ dir
|
|
28
45
|
* (resolved from THIS module's own on-disk location, never `process.cwd()`,
|
|
@@ -36,6 +53,13 @@ export function planText(p: {
|
|
|
36
53
|
export function jobNameTaken(name: string, opts?: {
|
|
37
54
|
jobsDir?: string;
|
|
38
55
|
}): boolean;
|
|
56
|
+
/**
|
|
57
|
+
* The repo a card names: Inputs line 1 (P7 — the Source box is gone; the first input IS the repo). `''` when the Inputs
|
|
58
|
+
* box does not parse (the card validator refuses that before anything uses this).
|
|
59
|
+
* @param {any} card
|
|
60
|
+
* @returns {string}
|
|
61
|
+
*/
|
|
62
|
+
export function cardSource(card: any): string;
|
|
39
63
|
/**
|
|
40
64
|
* Only the form's own fields, nothing else a request body might carry (`startFrom`, stray keys).
|
|
41
65
|
* @param {any} card
|
|
@@ -52,12 +76,12 @@ export function cardFields(card: any): Record<string, any>;
|
|
|
52
76
|
export function lockedFieldChanged(card: Record<string, any>, origin: Record<string, any>): string | null;
|
|
53
77
|
/**
|
|
54
78
|
* The spec a reuse signs: a COPY of the origin's signed spec with ONLY the open fields set from the card —
|
|
55
|
-
* `writeScope` from Destination, `budgetUsd` from the $ cap, `maxWallMs` from the Time cap (absent when blank), and the
|
|
79
|
+
* `writeScope` from Destination, `inputs` from the Inputs box (P7), `budgetUsd` from the $ cap, `maxWallMs` from the Time cap (absent when blank), and the
|
|
56
80
|
* worker (`provider`/`baseUrl`/`model`) from the Model Name chosen in Settings > Providers, spelled exactly as normal
|
|
57
81
|
* authoring spells it (`baseUrl` only when the row has one; `model` only when the Name is not the provider's default
|
|
58
82
|
* tier). A RUBRIC (soft-green) origin with no explicit `judge` first has its judge pinned to the ORIGIN's resolved judge
|
|
59
83
|
* identity — the judge must not change because the worker did (`resolveJobJudge`, the one spelling); an explicit
|
|
60
|
-
* `judge` is kept; a deterministic job has no judge to move.
|
|
84
|
+
* `judge` is kept; a deterministic job has no judge to move. The repo (Inputs line 1) is in a spec only as `inputs`. The copy
|
|
61
85
|
* hashes to a NEW `jobSpecHash` and the SAME `workflowKey` — the caller checks the second after building.
|
|
62
86
|
* @param {any} originSpec
|
|
63
87
|
* @param {Record<string, any>} card
|
|
@@ -67,7 +91,7 @@ export function lockedFieldChanged(card: Record<string, any>, origin: Record<str
|
|
|
67
91
|
export function buildReuseSpec(originSpec: any, card: Record<string, any>, rows?: readonly import("../providerrows.js").KeyRow[]): any;
|
|
68
92
|
/**
|
|
69
93
|
* `$0` validation for a REUSE start: the signed job carries the goal, checks and guardrails, so those boxes are not
|
|
70
|
-
* required here — only what the new session itself needs:
|
|
94
|
+
* required here — only what the new session itself needs: Inputs, a Destination, a Model that is a Settings Name,
|
|
71
95
|
* and the cap. (The spec built from the open boxes is validated by the route with `validateJob`.)
|
|
72
96
|
* @param {any} card
|
|
73
97
|
* @param {{rows?: readonly import('../providerrows.js').KeyRow[]}} [opts]
|
|
@@ -86,7 +110,7 @@ export function validateReuseCard(card: any, opts?: {
|
|
|
86
110
|
* relative to the repo, so an absolute path is refused — at $0, before any copy or model call. A FOLDER source (or a
|
|
87
111
|
* source that does not peek as a repo) keeps today's behaviour: its Destination is an absolute output directory.
|
|
88
112
|
* @param {string} destination
|
|
89
|
-
* @param {boolean} isRepoLike `looksLikeRepoSource(card
|
|
113
|
+
* @param {boolean} isRepoLike `looksLikeRepoSource(cardSource(card))`
|
|
90
114
|
* @returns {string|null} the plain refusal, or null when the Destination is fine
|
|
91
115
|
*/
|
|
92
116
|
export function repoDestinationProblem(destination: string, isRepoLike: boolean): string | null;
|
|
@@ -115,7 +139,7 @@ export function validateJobCard(card: any, opts?: {
|
|
|
115
139
|
* @param {any} card the validated job card (see {@link validateJobCard})
|
|
116
140
|
* @param {{env?: Record<string,string|undefined>, sessionsRoot?: string, home?: string, timeoutMs?: number,
|
|
117
141
|
* scout?: any, generate?: Function, confirmGenerate?: Function, authorFn?: Function,
|
|
118
|
-
* prepareSigningFn?: Function, npmCiFn?: Function, reuse?: {spec: any, workflowKey: string}}} [deps] `scout`..`prepareSigningFn` are
|
|
142
|
+
* prepareSigningFn?: Function, npmCiFn?: Function, draftThinking?: "on"|"off", reuse?: {spec: any, workflowKey: string}}} [deps] `scout`..`prepareSigningFn` are
|
|
119
143
|
* TEST SEAMS ONLY — see the note just above where each is read, below. `reuse` (Reuse workflow) is NOT a seam: the
|
|
120
144
|
* caller (`/api/author/start`) sets it only when the server's own same-job rule held.
|
|
121
145
|
* @returns {any} the session object
|
|
@@ -131,6 +155,7 @@ export function createSession(card: any, deps?: {
|
|
|
131
155
|
authorFn?: Function;
|
|
132
156
|
prepareSigningFn?: Function;
|
|
133
157
|
npmCiFn?: Function;
|
|
158
|
+
draftThinking?: "on" | "off";
|
|
134
159
|
reuse?: {
|
|
135
160
|
spec: any;
|
|
136
161
|
workflowKey: string;
|
|
@@ -149,22 +174,26 @@ export const STEP_LABELS: Readonly<Record<string, string>>;
|
|
|
149
174
|
* @type {Readonly<Record<string, keyof typeof STEP_LABELS>>}
|
|
150
175
|
*/
|
|
151
176
|
export const PHASE_STEP: Readonly<Record<string, keyof typeof STEP_LABELS>>;
|
|
177
|
+
/** the line under the plan bubble, in plain words (the bubble itself is drawn by the page's one `renderJobPlan`) */
|
|
178
|
+
export const PLAN_FOOTER: "Sign & run to confirm this plan, or Revise to edit the boxes and draft again.";
|
|
152
179
|
/** the form's fields, in card order — what `card.json` stores, verbatim (P5 item 3) */
|
|
153
180
|
export const CARD_FIELDS: readonly string[];
|
|
154
181
|
/**
|
|
155
182
|
* REUSE WORKFLOW (hamr 2026-10-03, replaces P5 item 3's same-job rule; Model opened 2026-10-04): a reuse card has exactly
|
|
156
|
-
* FIVE open boxes —
|
|
183
|
+
* FIVE open boxes — Inputs, Destination, Model, $ cap, Time cap — and every other box is the signed workflow, shown greyed and never
|
|
157
184
|
* editable. The page greys them; THIS is what refuses (the server never trusts the page). Changing any locked box
|
|
158
185
|
* is a different job: Clear the card, which drafts.
|
|
159
186
|
*/
|
|
160
187
|
export const REUSE_OPEN_FIELDS: readonly string[];
|
|
161
188
|
/** every card field that is NOT open on a reuse card, in card order */
|
|
162
189
|
export const REUSE_LOCKED_FIELDS: readonly string[];
|
|
163
|
-
export { nonRepoSourceMessage };
|
|
164
190
|
export type StepLine = {
|
|
165
191
|
id: string;
|
|
166
192
|
label: string;
|
|
167
193
|
status: "running" | "done" | "failed";
|
|
168
194
|
detail: string;
|
|
169
195
|
};
|
|
196
|
+
import { planFromConfirm } from './jobplan.js';
|
|
197
|
+
import { thinkingRowText } from '../thinking.js';
|
|
170
198
|
import { nonRepoSourceMessage } from '../source.js';
|
|
199
|
+
export { thinkingRowText, nonRepoSourceMessage };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/** @typedef {{name: string, cls: 'machine check'|'judge'|null}} PlanCheck */
|
|
2
|
+
/** @typedef {{n: number, text: string, rule: string, checks: PlanCheck[], refused: string[]}} PlanLine */
|
|
3
|
+
/** @typedef {{lines: PlanLine[], loose: PlanCheck[], notChecked: string[], alwaysOn: string[], older: boolean, goal?: string}} JobPlan */
|
|
4
|
+
/**
|
|
5
|
+
* `machine check` for a kind a command decides, `judge` for one that needs judgement; `null` for a stage whose kind is
|
|
6
|
+
* unknown (a hand-written command close has no kind: it is a command, so a machine check).
|
|
7
|
+
* @param {unknown} kind
|
|
8
|
+
* @returns {'machine check'|'judge'|null}
|
|
9
|
+
*/
|
|
10
|
+
export function checkClassOfKind(kind: unknown): "machine check" | "judge" | null;
|
|
11
|
+
/**
|
|
12
|
+
* The plan of a SIGNED spec. With `jobLines`, each stage lands under EACH line its `fromLine` array names (a stage with none is
|
|
13
|
+
* a mandatory guard: "Always on"), `closeDecl.refused` reasons land under their line, and `closeDecl.notes` are the
|
|
14
|
+
* drafter's own "not checked" words. Without `jobLines` (a spec that predates the job block) the signed goal sentence is
|
|
15
|
+
* line 1 and every stage name is a check under it — `older: true`.
|
|
16
|
+
* @param {any} spec
|
|
17
|
+
* @returns {JobPlan}
|
|
18
|
+
*/
|
|
19
|
+
export function planFromSpec(spec: any): JobPlan;
|
|
20
|
+
/**
|
|
21
|
+
* The plan of the confirm turn, before anything is drafted: the person's own job lines, the model's checks under the
|
|
22
|
+
* line each names, its own "not checked" words, and the real protections (code-owned) as "Always on".
|
|
23
|
+
* @param {{n: number, text: string, rule: string}[]|null|undefined} jobLines
|
|
24
|
+
* @param {{checkItems?: {text: string, fromLine: number[]|null}[], checks?: string[], notChecked?: string[], protections?: string[]}} plan
|
|
25
|
+
* @returns {JobPlan}
|
|
26
|
+
*/
|
|
27
|
+
export function planFromConfirm(jobLines: {
|
|
28
|
+
n: number;
|
|
29
|
+
text: string;
|
|
30
|
+
rule: string;
|
|
31
|
+
}[] | null | undefined, plan: {
|
|
32
|
+
checkItems?: {
|
|
33
|
+
text: string;
|
|
34
|
+
fromLine: number[] | null;
|
|
35
|
+
}[];
|
|
36
|
+
checks?: string[];
|
|
37
|
+
notChecked?: string[];
|
|
38
|
+
protections?: string[];
|
|
39
|
+
}): JobPlan;
|
|
40
|
+
export type PlanCheck = {
|
|
41
|
+
name: string;
|
|
42
|
+
cls: "machine check" | "judge" | null;
|
|
43
|
+
};
|
|
44
|
+
export type PlanLine = {
|
|
45
|
+
n: number;
|
|
46
|
+
text: string;
|
|
47
|
+
rule: string;
|
|
48
|
+
checks: PlanCheck[];
|
|
49
|
+
refused: string[];
|
|
50
|
+
};
|
|
51
|
+
export type JobPlan = {
|
|
52
|
+
lines: PlanLine[];
|
|
53
|
+
loose: PlanCheck[];
|
|
54
|
+
notChecked: string[];
|
|
55
|
+
alwaysOn: string[];
|
|
56
|
+
older: boolean;
|
|
57
|
+
goal?: string;
|
|
58
|
+
};
|
package/types/panel/server.d.ts
CHANGED
|
@@ -298,6 +298,26 @@ export function getRunRounds(runid: string, query?: {
|
|
|
298
298
|
}, opts?: {
|
|
299
299
|
home?: string;
|
|
300
300
|
}): any | null;
|
|
301
|
+
/**
|
|
302
|
+
* The Signed row of the Job tab: `YYYY-MM-DD HH:MM · <first 6 of specHash>`, the time being the run's FIRST `job-start`
|
|
303
|
+
* in local time (hamr, P7). `null` when either part is not on record — never a made-up stamp.
|
|
304
|
+
* @param {string|null|undefined} ts an ISO stamp @param {string|null|undefined} hash
|
|
305
|
+
* @returns {string|null}
|
|
306
|
+
*/
|
|
307
|
+
export function signedLine(ts: string | null | undefined, hash: string | null | undefined): string | null;
|
|
308
|
+
/**
|
|
309
|
+
* The Job box's text for a signed spec: the person's own numbered lines (a `~` line per entry of `rules`, or — for a spec
|
|
310
|
+
* signed before `rules` existed — per '; '-split piece of `rule`), or — for
|
|
311
|
+
* an older job that saved no job lines — the signed goal sentence as the one line.
|
|
312
|
+
* @param {any} spec @returns {string}
|
|
313
|
+
*/
|
|
314
|
+
export function jobTextFromSpec(spec: any): string;
|
|
315
|
+
/**
|
|
316
|
+
* The Inputs box's text for a signed spec: its numbered inputs, or — for an older job — `repo: <source>` from the
|
|
317
|
+
* caller's best knowledge of the source (or empty).
|
|
318
|
+
* @param {any} spec @param {string} source @returns {string}
|
|
319
|
+
*/
|
|
320
|
+
export function inputsTextFromSpec(spec: any, source: string): string;
|
|
301
321
|
/**
|
|
302
322
|
* `GET /api/runs/:runid/job` — the Job tab, filled from the first source
|
|
303
323
|
* that actually resolves (item 2, 2026-09-25), in order:
|
|
@@ -380,15 +400,17 @@ export function reuseLine(record: {
|
|
|
380
400
|
* $ cap and the Time cap — start at what the run had. `ok:false` when the run's signed job is not on disk (nothing
|
|
381
401
|
* to copy: change the job: Clear the card). `null` when the runid is not listed.
|
|
382
402
|
* @param {string} runid
|
|
383
|
-
* @param {{ home?: string, model?: string }} [opts] `model` = the Model box's current Name (the estimate counts only runs on that worker); absent = the card's own Model
|
|
403
|
+
* @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
|
|
384
404
|
* @returns {{ok: true, origin: {runid: string, job: string}, outcome: string|null, card: Record<string, any>, from: 'signed job',
|
|
385
405
|
* locked: readonly string[], open: readonly string[], note: string|null,
|
|
386
|
-
* specHash: string, workflowKey: string, spec: any, specPath: string,
|
|
406
|
+
* specHash: string, workflowKey: string, spec: any, specPath: string, specNamesModel: boolean,
|
|
407
|
+
* specWorker: {provider: string, endpoint: string, label: string},
|
|
387
408
|
* trackRecord: ReturnType<typeof trackRecordFor>, line: string}|{ok: false, error: string}|null}
|
|
388
409
|
*/
|
|
389
410
|
export function getStartFrom(runid: string, opts?: {
|
|
390
411
|
home?: string;
|
|
391
412
|
model?: string;
|
|
413
|
+
provider?: string;
|
|
392
414
|
}): {
|
|
393
415
|
ok: true;
|
|
394
416
|
origin: {
|
|
@@ -405,6 +427,12 @@ export function getStartFrom(runid: string, opts?: {
|
|
|
405
427
|
workflowKey: string;
|
|
406
428
|
spec: any;
|
|
407
429
|
specPath: string;
|
|
430
|
+
specNamesModel: boolean;
|
|
431
|
+
specWorker: {
|
|
432
|
+
provider: string;
|
|
433
|
+
endpoint: string;
|
|
434
|
+
label: string;
|
|
435
|
+
};
|
|
408
436
|
trackRecord: ReturnType<typeof trackRecordFor>;
|
|
409
437
|
line: string;
|
|
410
438
|
} | {
|
|
@@ -416,12 +444,13 @@ export function getStartFrom(runid: string, opts?: {
|
|
|
416
444
|
* that has at least one GREEN local run, newest green first. `runid` = that job's newest green run, so the page hands
|
|
417
445
|
* it to the existing start-from flow unchanged; `line` is `getStartFrom`'s own estimate line (never a second
|
|
418
446
|
* spelling). Local runs only — an imported job keeps its Reuse button in the Import view. $0, read-only.
|
|
419
|
-
* @param {{ home?: string, model?: string }} [opts] `model` passes through to the estimate line, as start-from's does
|
|
447
|
+
* @param {{ home?: string, model?: string, provider?: string }} [opts] `model` passes through to the estimate line, as start-from's does
|
|
420
448
|
* @returns {{job: string, runid: string, checkType: 'deterministic'|'rubric', line: string}[]}
|
|
421
449
|
*/
|
|
422
450
|
export function listReuseJobs(opts?: {
|
|
423
451
|
home?: string;
|
|
424
452
|
model?: string;
|
|
453
|
+
provider?: string;
|
|
425
454
|
}): {
|
|
426
455
|
job: string;
|
|
427
456
|
runid: string;
|
|
@@ -438,7 +467,7 @@ export function listReuseJobs(opts?: {
|
|
|
438
467
|
* signs it on this machine at [Sign & run]. Same card, same locked/open boxes as a run's reuse. `null` when no such
|
|
439
468
|
* imported job.
|
|
440
469
|
* @param {string} id
|
|
441
|
-
* @param {{ home?: string, model?: string }} [opts] `model` as for {@link getStartFrom}
|
|
470
|
+
* @param {{ home?: string, model?: string, provider?: string }} [opts] `model` as for {@link getStartFrom}
|
|
442
471
|
* @returns {{ok: true, origin: {runid: null, job: string, importId: string}, card: Record<string, any>, from: 'imported job',
|
|
443
472
|
* locked: readonly string[], open: readonly string[], note: string|null, specHash: string, workflowKey: string, spec: any,
|
|
444
473
|
* specPath: null, trackRecord: ReturnType<typeof trackRecordFor>, line: string}|{ok: false, error: string}|null}
|
|
@@ -446,6 +475,7 @@ export function listReuseJobs(opts?: {
|
|
|
446
475
|
export function getStartFromImport(id: string, opts?: {
|
|
447
476
|
home?: string;
|
|
448
477
|
model?: string;
|
|
478
|
+
provider?: string;
|
|
449
479
|
}): {
|
|
450
480
|
ok: true;
|
|
451
481
|
origin: {
|
package/types/planrun.d.ts
CHANGED
|
@@ -221,7 +221,7 @@ export function planPrompt(job: any, scoutBlob: string, reds: any[] | null, maxS
|
|
|
221
221
|
* item 27/M3 Part B), forwarded to every close invocation as
|
|
222
222
|
* `BARELOOP_CLOSE_DIR`
|
|
223
223
|
* @param {number} [opts.maxStepRounds] the shell's per-step rounds ceiling (validatePlan's bound)
|
|
224
|
-
* @param {boolean} [opts.scout=true] operator-only switch (docs/
|
|
224
|
+
* @param {boolean} [opts.scout=true] operator-only switch (docs/logs/SCOUT-CONTRAST.md):
|
|
225
225
|
* `false` on a FRESH run (no `resumeSeed`) skips the survey entirely — `scoutBlob`
|
|
226
226
|
* stays `''`, no `scout-start`/`scout-result`/`scout-empty` is emitted, and a single
|
|
227
227
|
* `scout-skipped {reason:'operator-off'}` records it (a RECORD, never silence — the
|