bareloop 0.7.0 → 0.8.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/types/reuse.d.ts CHANGED
@@ -174,7 +174,11 @@ export function selectBridge({ registry, job, ask, provider, pinned, shortlist,
174
174
  * **The declared fold, not a re-derivation.** A restarted try's own `try-start`
175
175
  * carries the fold it inherited (`priorSpentUsd`/`priorWallMs`), so a resume OF a
176
176
  * resume adds only its own new rounds. Re-deriving from the whole file would bill an
177
- * abandoned attempt twice.
177
+ * abandoned attempt twice. The REPLAN ledger (`priorReplans`/`priorReplanGrantUsed`)
178
+ * folds on this same mechanism and deliberately not on `readGradeSeed`'s: a grade seed
179
+ * feeds a readout, so its documented one-leg-per-resume shortening can only under-claim
180
+ * a direction, while an under-claimed CEILING is a refilled allowance and every kill
181
+ * would buy one (PRD v1.12 — the replan bound is the RUN's).
178
182
  *
179
183
  * **KNOWN LIMIT, stated rather than discovered later.** A call that was killed BEFORE it
180
184
  * returned left no event at all — no `worker-round`, no `selection-result` — so money it
package/types/run.d.ts CHANGED
@@ -74,6 +74,15 @@
74
74
  * chain, not just the leg: without them a leg that re-grades an unchanged tree reports
75
75
  * `flat` — "revise the goal" — on a run that was converging when the money ran out.
76
76
  * Counts and stage names only; no close bytes cross this seam. Absent is the cold path.
77
+ * @param {{count?: number, grantUsed?: boolean}|null} [opts.resumeReplans] RESUME — the
78
+ * replan LEDGER the chain has already spent (`readResume`'s `restart.replans` /
79
+ * `restart.replanGrantUsed`), forwarded to the plan flow, which seeds its ceiling with
80
+ * it. Its sibling above feeds a READOUT; this one feeds a BOUND, and that is the whole
81
+ * difference: `replanned`/`varianceGrantUsed` are locals in `runPlan`, so without this
82
+ * every kill hands the next leg a fresh allowance of an allowance PRD v1.12 makes the
83
+ * RUN's ("unlimited replanning launders thrash as adaptation"). It also rides onto this
84
+ * run's `job-start` as `priorReplans`, the declared-fold precedent `priorSpentUsd`
85
+ * already sets, so a resume OF a resume folds once. Absent is the cold path.
77
86
  * @param {boolean} [opts.layerRoot=false] Layer R (within-run ratchet) — shell
78
87
  * territory, threaded to the plan flow. Defaults OFF
79
88
  * (decided 2026-07-21): fixation is extinct on every current job (F41), so
@@ -86,7 +95,7 @@
86
95
  * 'close-red' | 'close-unsupported' | 'recipe-stale' | 'pricing-red' | 'provider-red' |
87
96
  * 'interpreter-red' | 'cap-halt' | 'wall-halt' | 'step-stalled' | `step-red:<id>`
88
97
  */
89
- export function runJob(rawSpec: object | string, { approvals, workdir, provider, nativeProvider, providerFor, emit, capRuns, strikeLimit, shellCapUsd, closeTimeoutMs, layerRoot, bridge, priorSpentUsd, priorSpendComplete, priorWallMs, resumeSeed, resumeGrades }: {
98
+ export function runJob(rawSpec: object | string, { approvals, workdir, provider, nativeProvider, providerFor, emit, capRuns, strikeLimit, shellCapUsd, closeTimeoutMs, layerRoot, bridge, priorSpentUsd, priorSpendComplete, priorWallMs, resumeSeed, resumeGrades, resumeReplans }: {
90
99
  approvals: unknown;
91
100
  workdir: string;
92
101
  provider: any;
@@ -111,6 +120,10 @@ export function runJob(rawSpec: object | string, { approvals, workdir, provider,
111
120
  stage?: string | null;
112
121
  value?: number | null;
113
122
  }[] | undefined;
123
+ resumeReplans?: {
124
+ count?: number;
125
+ grantUsed?: boolean;
126
+ } | null | undefined;
114
127
  layerRoot?: boolean | undefined;
115
128
  }): Promise<string>;
116
129
  export type Red = {
@@ -62,4 +62,54 @@ export function redactSecrets(raw: unknown): string;
62
62
  * @param {(code: string, path: string, detail?: string) => void} red
63
63
  */
64
64
  export function sweepSecretLiterals(root: any, red: (code: string, path: string, detail?: string) => void): void;
65
+ /**
66
+ * F49 — a heuristic reject for the catastrophic-backtracking footgun: an
67
+ * unbounded quantifier applied to a group whose body itself repeats unboundedly
68
+ * (`(a+)+`, `(\d*)*`, `([a-z]+){1,}`) — including through a redundant wrapping
69
+ * group (`((a+))+`, `(?:(a+))*`), which is the SAME exponential class as `(a+)+`
70
+ * and is caught by propagating the inner repeat up through the wrapper. Such a
71
+ * pattern can hang `RegExp.test` for seconds on a short crafted body, and THREE
72
+ * fields feed it to an evaluator with NO timeout — one per document:
73
+ * - the AGENT's `artifact-written.pattern`, run by `evalExits` (F49, the
74
+ * original site). Self-DoS only: the agent authors both the pattern and
75
+ * (via the worker) the artifact, so a hang burns only its own run's
76
+ * wall-clock, and there is no arbiter compromise — it cannot escape the
77
+ * fence, forge a green, or leak a secret.
78
+ * - the OPERATOR's `judged.pattern` (`runClose`) and `gapKeep` (`boundGap`),
79
+ * compiled and run against close output in BARELOOP'S OWN PROCESS. These
80
+ * are worse than an operator self-DoS, and the reason is F67's lesson: the
81
+ * regex blocks the MAIN EVENT LOOP, so the in-process stall fuse — a timer
82
+ * in that same loop — cannot fire. The run dies to the OUTSIDE watchdog and
83
+ * is read as a model stall, so a bad regex in a SIGNED spec presents as a
84
+ * provider problem. MEASURED: `boundGap(stream, '(a+)+$')` on a 40-char
85
+ * body does not finish in 20s.
86
+ * So the reject targets the dominant exponential class and fails it as a
87
+ * mechanical gap at the validation gate, before any tokens burn. A full ReDoS
88
+ * analyzer needs a real regex engine (an external native dep we do not take for
89
+ * a LOW issue); exotic overlapping-alternation blowup is out of scope by
90
+ * decision (PARKED to the close-authoring rung — PRD v1.55).
91
+ *
92
+ * SCOPE IS ASYMMETRIC, both directions named on purpose:
93
+ * - false NEGATIVE: overlapping-alternation blowup (`(a|ab)+`-class) is not
94
+ * detected — there is no inner QUANTIFIER to find, so the shape scan cannot
95
+ * see it; the blowup comes from overlapping alternation BRANCHES under a
96
+ * repeat. A genuine limit of the approach, not a bug in it. Widening the
97
+ * detector changes which SIGNED specs are admissible, which is
98
+ * arbiter-adjacent — parked, not chased (PRD v1.55).
99
+ * - false POSITIVE: a group whose repetitions are disambiguated by a literal
100
+ * anchor/delimiter (`(?:^- .+$\n?)+`, `(?:CHANGELOG:.+\n)+`) is FLAGGED even
101
+ * though a real engine runs it linearly — the scan sees the nested-quantifier
102
+ * SHAPE, not the disambiguation. Rejecting it is the FAIL-SAFE direction (it
103
+ * never admits an unsafe pattern), and the cost is bounded: the plan drafter
104
+ * gets a mechanical gap and rewrites (drop the outer `+`, or match once).
105
+ * Detecting "safe because anchored" needs the same real engine we declined,
106
+ * and guessing it wrong would ADMIT an exponential pattern — so the shape
107
+ * reject stands, and the over-rejection is a named, accepted limitation.
108
+ *
109
+ * The input is guaranteed to compile as a RegExp (checked first by the caller),
110
+ * so this scan assumes valid, balanced JS regex syntax.
111
+ * @param {string} src a compiled regex source string
112
+ * @returns {boolean} true iff a nested unbounded quantifier is present
113
+ */
114
+ export function hasNestedQuantifier(src: string): boolean;
65
115
  export const SECRET_PATTERNS: RegExp[];