@tangle-network/agent-eval 0.108.1 → 0.109.1

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.
@@ -17,7 +17,7 @@ import {
17
17
  runBenchmarkAdapter,
18
18
  summarizeBenchmarkCampaign
19
19
  } from "../chunk-T6W5ADLG.js";
20
- import "../chunk-6SKVFBTR.js";
20
+ import "../chunk-R6D7NEYJ.js";
21
21
  import "../chunk-OVPVM4JC.js";
22
22
  import "../chunk-3PFZBGMR.js";
23
23
  import "../chunk-VI2UW6B6.js";
@@ -727,6 +727,80 @@ declare function dimensionRegressions(candidate: Map<string, Record<string, Judg
727
727
  seed?: number;
728
728
  }): DimensionRegression[];
729
729
 
730
+ /**
731
+ * Evidence grounding for reflective optimizers (GEPA-style revise loops).
732
+ *
733
+ * Two failure modes recur when an LLM revises an artifact from raw rollout
734
+ * traces (first measured in agent-lab R358, where naive reflection REGRESSED
735
+ * the score 0.375 -> 0.125 before these helpers fixed it):
736
+ *
737
+ * 1. The environment often hides WHY a rollout failed - a tool call can
738
+ * succeed while an invisible downstream check fails - so the reviser
739
+ * cannot see the cause in the transcript. The only reliable signal is the
740
+ * field-level difference between what passing and failing rollouts did.
741
+ * `rolloutArgumentDiff` computes that difference deterministically so the
742
+ * reviser is handed the diff instead of being trusted to derive it.
743
+ *
744
+ * 2. Revisers invent plausible-but-wrong literal values ("use 'new'",
745
+ * "use 'sent'") that no passing rollout ever used, turning every rollout
746
+ * into a failure. `classifyUngroundedLiterals` mechanically detects them,
747
+ * separating HARMFUL literals (ones failing rollouts actually used -
748
+ * proven damage) from benign illustrations (e.g. a name example like
749
+ * 'Doe'), so callers can hard-reject the former and merely log the latter.
750
+ * Rejecting every ungrounded quoted word is too blunt: it killed a run
751
+ * over a surname illustration before the severity split existed.
752
+ *
753
+ * Pure data in, data out: no LLM calls, no filesystem, no domain knowledge.
754
+ */
755
+ /** One tool/action call observed in a rollout: a name plus its arguments. */
756
+ interface RolloutCall {
757
+ readonly name: string;
758
+ readonly args: Readonly<Record<string, unknown>>;
759
+ }
760
+ /** A scored rollout: its calls plus the scalar outcome used to split pass/fail. */
761
+ interface ScoredRollout {
762
+ /** Caller-meaningful identifier (task id, cell id) used only for reporting. */
763
+ readonly id: string;
764
+ /** Scalar outcome in [0, 1]; `passThreshold` splits passing from failing. */
765
+ readonly score: number;
766
+ readonly calls: readonly RolloutCall[];
767
+ }
768
+ interface RolloutArgumentDiffOptions {
769
+ /** Rollouts with `score >= passThreshold` count as passing. Default 1. */
770
+ readonly passThreshold?: number;
771
+ /** Max distinct values listed per field per side in the rendered text. Default 4. */
772
+ readonly maxValuesPerField?: number;
773
+ }
774
+ interface RolloutArgumentDiff {
775
+ /** Human/LLM-readable per-field diff, one line per field. */
776
+ readonly text: string;
777
+ /** Lowercased stringified argument values seen in passing rollouts. */
778
+ readonly passingValues: ReadonlySet<string>;
779
+ /** Lowercased stringified argument values seen in failing rollouts. */
780
+ readonly failingValues: ReadonlySet<string>;
781
+ }
782
+ /**
783
+ * Deterministic per-field diff of call arguments between passing and failing
784
+ * rollouts. A field set by failing rollouts but left unset by passing ones is
785
+ * the classic poison-input signature; a field whose values differ across the
786
+ * split points at the correct value. Feed `text` to the reviser verbatim.
787
+ */
788
+ declare function rolloutArgumentDiff(rollouts: readonly ScoredRollout[], opts?: RolloutArgumentDiffOptions): RolloutArgumentDiff;
789
+ interface UngroundedLiteralReport {
790
+ /** Quoted single-word literals in the text that no passing rollout used. */
791
+ readonly ungrounded: readonly string[];
792
+ /** The subset failing rollouts actually used - prescribing these is proven harmful. */
793
+ readonly harmful: readonly string[];
794
+ }
795
+ /**
796
+ * Scan revised artifact text for single-quoted single-word literals (the
797
+ * "use exactly 'new'" pattern) that appear in no passing rollout's argument
798
+ * values. Multi-word quotes pass (they are prose, not prescriptions).
799
+ * Callers should reject on `harmful` (with a bounded retry) and at most log
800
+ * `ungrounded` - see the module header for why the severities differ.
801
+ */
802
+ declare function classifyUngroundedLiterals(text: string, diff: Pick<RolloutArgumentDiff, 'passingValues' | 'failingValues'>): UngroundedLiteralReport;
803
+
730
804
  /**
731
805
  * Filesystem `LabeledScenarioStore` adapter. The default capture sink for
732
806
  * traces + eval artifacts. Production deployments typically swap for a
@@ -2018,6 +2092,76 @@ interface CampaignBreakdown {
2018
2092
  * on: mean score per judge dimension + per-scenario composite. */
2019
2093
  declare function campaignBreakdown<TArtifact, TScenario extends Scenario>(campaign: CampaignResult<TArtifact, TScenario>): CampaignBreakdown;
2020
2094
 
2095
+ /**
2096
+ * Single-run lock for evaluations that share one mutable environment.
2097
+ *
2098
+ * Two concurrent runs against a shared stateful gym silently corrupt each
2099
+ * other: each resets/mutates environment state mid-cell of the other, and
2100
+ * every score from both becomes garbage that LOOKS like worker variance
2101
+ * (agent-lab R357 burned hours on flip-flopping scores before tracing them
2102
+ * to exactly this). The fix is a pid lockfile: refuse to start while a live
2103
+ * holder exists, reclaim stale locks whose pid is gone, release only if the
2104
+ * lock is still ours.
2105
+ *
2106
+ * `alsoCheck` exists because independent runners can guard the same shared
2107
+ * resource with differently named lockfiles; a runner must respect all of
2108
+ * them even though it writes only its own.
2109
+ */
2110
+ interface SingleRunLockOptions {
2111
+ /** Lockfile this runner writes (and checks). */
2112
+ readonly lockPath: string;
2113
+ /** Other runners' lockfiles guarding the same resource; checked, never written. */
2114
+ readonly alsoCheck?: readonly string[];
2115
+ /** Install a process 'exit' hook that releases the lock. Default true. */
2116
+ readonly releaseOnExit?: boolean;
2117
+ /** Owner pid recorded in the lockfile. Default process.pid. */
2118
+ readonly pid?: number;
2119
+ }
2120
+ interface SingleRunLock {
2121
+ /** Remove the lockfile if this process still owns it. Idempotent. */
2122
+ release(): void;
2123
+ }
2124
+ /**
2125
+ * Acquire the lock or throw naming the live holder. A stale lock (holder pid
2126
+ * no longer running) is reclaimed silently.
2127
+ */
2128
+ declare function acquireSingleRunLock(opts: SingleRunLockOptions): SingleRunLock;
2129
+
2130
+ /**
2131
+ * Transient-transport-failure classification for dispatch retry policies.
2132
+ *
2133
+ * When an eval cell dies, the harness must decide: retry (the infrastructure
2134
+ * hiccuped - a 502 storm, an admission-queue rejection, a dropped stream) or
2135
+ * score it (the agent genuinely failed). Getting this wrong corrupts results
2136
+ * in both directions: scoring transport hiccups as failures buries real
2137
+ * effects under noise (agent-lab R353 found 5/30 identical repeats were 502s
2138
+ * scored as task failures), while retrying genuine failures silently drops
2139
+ * the hard cells and inflates every arm.
2140
+ *
2141
+ * Full-duration timeouts are the deliberate knob: on saturated shared
2142
+ * infrastructure a timeout usually means the request never got a slot
2143
+ * (retry it), but on unthrottled infrastructure it means the agent flailed
2144
+ * on the task until the clock ran out (a real score-0). Both readings were
2145
+ * needed in practice within one week, so the classifier takes it as an
2146
+ * option instead of hardcoding either.
2147
+ */
2148
+ interface TransientFailureOptions {
2149
+ /**
2150
+ * Treat full-duration timeouts ("timeout after 180000ms") as transient.
2151
+ * Enable on saturated shared infrastructure where queue starvation eats
2152
+ * the clock; leave off when the agent had the resources and simply failed.
2153
+ * Default false.
2154
+ */
2155
+ readonly retryFullDurationTimeouts?: boolean;
2156
+ /** Additional caller-specific transient patterns. */
2157
+ readonly extraPatterns?: readonly RegExp[];
2158
+ }
2159
+ /**
2160
+ * True when the error text describes an infrastructure hiccup that should be
2161
+ * retried rather than scored. Empty/undefined input is not transient.
2162
+ */
2163
+ declare function isTransientTransportFailure(message: string | null | undefined, opts?: TransientFailureOptions): boolean;
2164
+
2021
2165
  /**
2022
2166
  * VCS-pluggable worktree adapter. One improvement = one worktree, PR-like
2023
2167
  * (multiple commits allowed). A code-tier proposer's `propose()` creates a
@@ -2075,4 +2219,4 @@ declare function gitWorktreeAdapter(opts: GitWorktreeAdapterOptions): WorktreeAd
2075
2219
  * as a ref under the adapter's worktree dir. */
2076
2220
  declare function resolveWorktreePath(surface: CodeSurface, worktreeDir?: string): string;
2077
2221
 
2078
- export { type AcceptedEdit, type AceProposerOptions, type AnalystArtifact, type AnalystScenario, type ApplySkillPatchResult, type BuildAnalystSurfaceDispatchOptions, type CampaignBreakdown, CampaignResult, CampaignRunPlan, CampaignStorage, CodeSurface, type CompareProposersOptions, type DimensionRegression, type DiscriminationScore, DispatchContext, type EvalFixture, type EvalFixtureFile, type EvalFixtureLoadOptions, type EvalFixtureRunPlan, type EvalFixtureScenario, type EvalFixtureValidationMode, type FailureModeRecallJudgeOptions, type FapoAttributionSignals, type FapoEntryConfig, type FapoFailureCluster, type FapoOptimizationLevel, type FapoProposerOptions, type FapoReviewInput, type FapoReviewIssue, type FapoReviewResult, type FapoScopeContract, FsLabeledScenarioStore, type FsLabeledScenarioStoreOptions, Gate, GenerationRecord, type GitWorktreeAdapterOptions, type Governor, type GovernorContext, type GovernorOp, type HaloProposerOptions, type HeldoutSignificance, type HeldoutSignificanceOptions, type HeuristicGovernorOptions, type JsonPrimitive, type JsonValue, JudgeConfig, JudgeScore, LabelTrust, LabeledScenarioRecord, LabeledScenarioSampleArgs, LabeledScenarioSource, LabeledScenarioStore, LabeledScenarioStoreError, LabeledScenarioWrite, Lineage, type LineageEdge, type LineageGraph, type LineageNode, type LineageNodeInput, type LineageStore, type LoadEvalFixtureScenariosOptions, type MemoryCurationProposerOptions, MutableSurface, type NeutralizationGateOptions, type OptimizerEntryConfig, type PairedHoldout, type ParameterCandidate, type ParameterChange, type ParameterSweepProposerOptions, PlanCampaignRunOptions, type PlanEvalFixtureRunOptions, type PlaybackContext, type PlaybackDriver, type PlaybackStep, type PolicyEditProposerOptions, type ProfileDispatchFn, ProfileMatrixError, type ProfileSummary, ProposeContext, type ProposePatchesArgs, ProposedCandidate, type ProposerComparison, type ProposerEntry, type ProposerPairwise, type ProposerScore, type RejectedEdit, RunCampaignOptions, RunImprovementLoopOptions, type RunLineageLoopOptions, type RunLineageLoopResult, type RunLineageLoopSeed, type RunLineageOptions, type RunLineageResult, type RunLineageSeed, type RunLineageStepResult, type RunProfileMatrixOptions, type RunProfileMatrixResult, type RunSkillOptOptions, type RunSkillOptResult, Scenario, type ScenarioRollup, type ScenarioSignal, type ScoreboardRenderOptions, type ScoreboardRow, type ScoreboardSummary, type SequentialDecideFn, type SequentialDecideOptions, type SequentialDecision, type SequentialObservation, type SequentialPairedGate, type SequentialPairedGateOptions, type SkillOptEpochRecord, type SkillOptEvidence, type SkillOptProposer, type SkillOptProposerOptions, type SkillPatch, type SkillPatchOp, SkillPatchParseError, type SkillPatchRejection, SurfaceProposer, type SurfaceScore, type TraceAnalystProposerOptions, type UserStory, type UserStoryVerdict, type Worktree, type WorktreeAdapter, WorktreeAdapterError, aceProposer, applySkillPatch, buildAnalystSurfaceDispatch, callbackGovernor, campaignBreakdown, campaignMeanComposite, compareProposers, detectScale, dimensionRegressions, discoverEvalFixtures, extractFapoAttributionSignals, failureModeRecallJudge, fapoEscalationEntry, fapoProposer, fsLineageStore, gepaParetoEntry, gepaReflectionEntry, gitWorktreeAdapter, haloProposer, heldoutSignificance, heuristicGovernor, lineageNodeId, loadEvalFixture, loadEvalFixtureScenarios, makePlaybackDispatch, memLineageStore, memoryCurationProposer, neutralizationGate, neutralizeText, pairHoldout, parameterSweepProposer, parseSkillPatchResponse, patchEditCount, planEvalFixtureRun, policyEditProposer, renderScoreboardMarkdown, resolveRunDir, resolveWorktreePath, runLineage, runLineageLoop, runProfileMatrix, runSkillOpt, scoreDiscrimination, scoreUserStory, scoreboardSummary, selectDiscriminative, sequentialDecide, sequentialPairedGate, skillOptEntry, skillOptProposer, tangleTracesRoot, traceAnalystProposer, userStoryScoreboard };
2222
+ export { type AcceptedEdit, type AceProposerOptions, type AnalystArtifact, type AnalystScenario, type ApplySkillPatchResult, type BuildAnalystSurfaceDispatchOptions, type CampaignBreakdown, CampaignResult, CampaignRunPlan, CampaignStorage, CodeSurface, type CompareProposersOptions, type DimensionRegression, type DiscriminationScore, DispatchContext, type EvalFixture, type EvalFixtureFile, type EvalFixtureLoadOptions, type EvalFixtureRunPlan, type EvalFixtureScenario, type EvalFixtureValidationMode, type FailureModeRecallJudgeOptions, type FapoAttributionSignals, type FapoEntryConfig, type FapoFailureCluster, type FapoOptimizationLevel, type FapoProposerOptions, type FapoReviewInput, type FapoReviewIssue, type FapoReviewResult, type FapoScopeContract, FsLabeledScenarioStore, type FsLabeledScenarioStoreOptions, Gate, GenerationRecord, type GitWorktreeAdapterOptions, type Governor, type GovernorContext, type GovernorOp, type HaloProposerOptions, type HeldoutSignificance, type HeldoutSignificanceOptions, type HeuristicGovernorOptions, type JsonPrimitive, type JsonValue, JudgeConfig, JudgeScore, LabelTrust, LabeledScenarioRecord, LabeledScenarioSampleArgs, LabeledScenarioSource, LabeledScenarioStore, LabeledScenarioStoreError, LabeledScenarioWrite, Lineage, type LineageEdge, type LineageGraph, type LineageNode, type LineageNodeInput, type LineageStore, type LoadEvalFixtureScenariosOptions, type MemoryCurationProposerOptions, MutableSurface, type NeutralizationGateOptions, type OptimizerEntryConfig, type PairedHoldout, type ParameterCandidate, type ParameterChange, type ParameterSweepProposerOptions, PlanCampaignRunOptions, type PlanEvalFixtureRunOptions, type PlaybackContext, type PlaybackDriver, type PlaybackStep, type PolicyEditProposerOptions, type ProfileDispatchFn, ProfileMatrixError, type ProfileSummary, ProposeContext, type ProposePatchesArgs, ProposedCandidate, type ProposerComparison, type ProposerEntry, type ProposerPairwise, type ProposerScore, type RejectedEdit, type RolloutArgumentDiff, type RolloutArgumentDiffOptions, type RolloutCall, RunCampaignOptions, RunImprovementLoopOptions, type RunLineageLoopOptions, type RunLineageLoopResult, type RunLineageLoopSeed, type RunLineageOptions, type RunLineageResult, type RunLineageSeed, type RunLineageStepResult, type RunProfileMatrixOptions, type RunProfileMatrixResult, type RunSkillOptOptions, type RunSkillOptResult, Scenario, type ScenarioRollup, type ScenarioSignal, type ScoreboardRenderOptions, type ScoreboardRow, type ScoreboardSummary, type ScoredRollout, type SequentialDecideFn, type SequentialDecideOptions, type SequentialDecision, type SequentialObservation, type SequentialPairedGate, type SequentialPairedGateOptions, type SingleRunLock, type SingleRunLockOptions, type SkillOptEpochRecord, type SkillOptEvidence, type SkillOptProposer, type SkillOptProposerOptions, type SkillPatch, type SkillPatchOp, SkillPatchParseError, type SkillPatchRejection, SurfaceProposer, type SurfaceScore, type TraceAnalystProposerOptions, type TransientFailureOptions, type UngroundedLiteralReport, type UserStory, type UserStoryVerdict, type Worktree, type WorktreeAdapter, WorktreeAdapterError, aceProposer, acquireSingleRunLock, applySkillPatch, buildAnalystSurfaceDispatch, callbackGovernor, campaignBreakdown, campaignMeanComposite, classifyUngroundedLiterals, compareProposers, detectScale, dimensionRegressions, discoverEvalFixtures, extractFapoAttributionSignals, failureModeRecallJudge, fapoEscalationEntry, fapoProposer, fsLineageStore, gepaParetoEntry, gepaReflectionEntry, gitWorktreeAdapter, haloProposer, heldoutSignificance, heuristicGovernor, isTransientTransportFailure, lineageNodeId, loadEvalFixture, loadEvalFixtureScenarios, makePlaybackDispatch, memLineageStore, memoryCurationProposer, neutralizationGate, neutralizeText, pairHoldout, parameterSweepProposer, parseSkillPatchResponse, patchEditCount, planEvalFixtureRun, policyEditProposer, renderScoreboardMarkdown, resolveRunDir, resolveWorktreePath, rolloutArgumentDiff, runLineage, runLineageLoop, runProfileMatrix, runSkillOpt, scoreDiscrimination, scoreUserStory, scoreboardSummary, selectDiscriminative, sequentialDecide, sequentialPairedGate, skillOptEntry, skillOptProposer, tangleTracesRoot, traceAnalystProposer, userStoryScoreboard };
@@ -6,9 +6,11 @@ import {
6
6
  SkillPatchParseError,
7
7
  WorktreeAdapterError,
8
8
  aceProposer,
9
+ acquireSingleRunLock,
9
10
  applySkillPatch,
10
11
  buildAnalystSurfaceDispatch,
11
12
  callbackGovernor,
13
+ classifyUngroundedLiterals,
12
14
  compareProposers,
13
15
  discoverEvalFixtures,
14
16
  extractFapoAttributionSignals,
@@ -21,6 +23,7 @@ import {
21
23
  gitWorktreeAdapter,
22
24
  haloProposer,
23
25
  heuristicGovernor,
26
+ isTransientTransportFailure,
24
27
  lineageNodeId,
25
28
  llmJudge,
26
29
  loadEvalFixture,
@@ -37,6 +40,7 @@ import {
37
40
  policyEditProposer,
38
41
  renderScoreboardMarkdown,
39
42
  resolveWorktreePath,
43
+ rolloutArgumentDiff,
40
44
  runLineage,
41
45
  runLineageLoop,
42
46
  runProfileMatrix,
@@ -51,7 +55,7 @@ import {
51
55
  skillOptProposer,
52
56
  traceAnalystProposer,
53
57
  userStoryScoreboard
54
- } from "../chunk-6SKVFBTR.js";
58
+ } from "../chunk-R6D7NEYJ.js";
55
59
  import {
56
60
  buildEvidenceVector,
57
61
  buildLoopProvenanceRecord,
@@ -117,6 +121,7 @@ export {
117
121
  SkillPatchParseError,
118
122
  WorktreeAdapterError,
119
123
  aceProposer,
124
+ acquireSingleRunLock,
120
125
  applySkillPatch,
121
126
  buildAnalystSurfaceDispatch,
122
127
  buildEvidenceVector,
@@ -124,6 +129,7 @@ export {
124
129
  callbackGovernor,
125
130
  campaignBreakdown,
126
131
  campaignMeanComposite,
132
+ classifyUngroundedLiterals,
127
133
  compareProposers,
128
134
  composeGate,
129
135
  countSentenceEdits,
@@ -151,6 +157,7 @@ export {
151
157
  heuristicGovernor,
152
158
  inMemoryCampaignStorage,
153
159
  isProposedCandidate,
160
+ isTransientTransportFailure,
154
161
  labelTrustRank,
155
162
  lineageNodeId,
156
163
  llmJudge,
@@ -178,6 +185,7 @@ export {
178
185
  renderScoreboardMarkdown,
179
186
  resolveRunDir,
180
187
  resolveWorktreePath,
188
+ rolloutArgumentDiff,
181
189
  runCampaign,
182
190
  runEval,
183
191
  runImprovementLoop,
@@ -1378,6 +1378,57 @@ function sequentialDecide(options = {}) {
1378
1378
  return decide;
1379
1379
  }
1380
1380
 
1381
+ // src/campaign/grounded-reflection.ts
1382
+ function rolloutArgumentDiff(rollouts, opts = {}) {
1383
+ const passThreshold = opts.passThreshold ?? 1;
1384
+ const maxValues = opts.maxValuesPerField ?? 4;
1385
+ const collect = (pass) => {
1386
+ const byField = /* @__PURE__ */ new Map();
1387
+ for (const r of rollouts) {
1388
+ if (pass !== r.score >= passThreshold) continue;
1389
+ for (const c of r.calls) {
1390
+ for (const [k, v] of Object.entries(c.args)) {
1391
+ const set = byField.get(k) ?? /* @__PURE__ */ new Set();
1392
+ set.add(String(v));
1393
+ byField.set(k, set);
1394
+ }
1395
+ }
1396
+ }
1397
+ return byField;
1398
+ };
1399
+ const passing = collect(true);
1400
+ const failing = collect(false);
1401
+ const lines = [];
1402
+ for (const field of /* @__PURE__ */ new Set([...passing.keys(), ...failing.keys()])) {
1403
+ const pv = [...passing.get(field) ?? []].slice(0, maxValues);
1404
+ const fv = [...failing.get(field) ?? []].slice(0, maxValues);
1405
+ const render = (vals) => vals.length ? JSON.stringify(vals) : "NOT SET (omitted)";
1406
+ lines.push(` ${field}: passing runs -> ${render(pv)} | failing runs -> ${render(fv)}`);
1407
+ }
1408
+ const lower = (m) => {
1409
+ const out = /* @__PURE__ */ new Set();
1410
+ for (const vals of m.values()) for (const v of vals) out.add(v.toLowerCase());
1411
+ return out;
1412
+ };
1413
+ return {
1414
+ text: lines.join("\n") || " (no calls observed)",
1415
+ passingValues: lower(passing),
1416
+ failingValues: lower(failing)
1417
+ };
1418
+ }
1419
+ function classifyUngroundedLiterals(text, diff) {
1420
+ const ungrounded = /* @__PURE__ */ new Set();
1421
+ for (const m of text.matchAll(/'([a-z][a-z_-]{1,19})'/gi)) {
1422
+ const w = m[1].toLowerCase();
1423
+ if (!diff.passingValues.has(w)) ungrounded.add(w);
1424
+ }
1425
+ const all = [...ungrounded];
1426
+ return {
1427
+ ungrounded: all,
1428
+ harmful: all.filter((w) => diff.failingValues.has(w))
1429
+ };
1430
+ }
1431
+
1381
1432
  // src/campaign/labeled-store/fs-adapter.ts
1382
1433
  import { createHash as createHash4 } from "crypto";
1383
1434
  import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, writeFileSync } from "fs";
@@ -4169,9 +4220,56 @@ function selectDiscriminative(signals, k, opts) {
4169
4220
  return [...nonTied, ...fill].map((s) => s.scenarioId);
4170
4221
  }
4171
4222
 
4223
+ // src/campaign/single-run-lock.ts
4224
+ import { existsSync as existsSync3, readFileSync as readFileSync3, unlinkSync, writeFileSync as writeFileSync3 } from "fs";
4225
+ function liveHolder(path) {
4226
+ if (!existsSync3(path)) return null;
4227
+ const holder = Number(readFileSync3(path, "utf8").trim());
4228
+ if (!Number.isFinite(holder) || holder <= 0) return null;
4229
+ try {
4230
+ process.kill(holder, 0);
4231
+ return holder;
4232
+ } catch {
4233
+ return null;
4234
+ }
4235
+ }
4236
+ function acquireSingleRunLock(opts) {
4237
+ const pid = opts.pid ?? process.pid;
4238
+ for (const path of [opts.lockPath, ...opts.alsoCheck ?? []]) {
4239
+ const holder = liveHolder(path);
4240
+ if (holder !== null && holder !== pid) {
4241
+ throw new Error(
4242
+ `single-run lock held by live pid ${holder} (${path}); refusing a concurrent run on the shared resource`
4243
+ );
4244
+ }
4245
+ }
4246
+ writeFileSync3(opts.lockPath, String(pid));
4247
+ const release = () => {
4248
+ try {
4249
+ if (existsSync3(opts.lockPath) && readFileSync3(opts.lockPath, "utf8").trim() === String(pid)) {
4250
+ unlinkSync(opts.lockPath);
4251
+ }
4252
+ } catch {
4253
+ }
4254
+ };
4255
+ if (opts.releaseOnExit ?? true) process.on("exit", release);
4256
+ return { release };
4257
+ }
4258
+
4259
+ // src/campaign/transient-failure.ts
4260
+ var BASE_TRANSIENT = /\b50[234]\b|no stream output|produced no stream|admission timed out|admission_rejected|queue_timeout|fetch failed|ECONNRESET|This operation was aborted/i;
4261
+ var TIMEOUT_PATTERN = /timeout after \d+ ?ms|cli-bridge timeout/i;
4262
+ function isTransientTransportFailure(message, opts = {}) {
4263
+ if (!message) return false;
4264
+ if (BASE_TRANSIENT.test(message)) return true;
4265
+ if ((opts.retryFullDurationTimeouts ?? false) && TIMEOUT_PATTERN.test(message)) return true;
4266
+ for (const p of opts.extraPatterns ?? []) if (p.test(message)) return true;
4267
+ return false;
4268
+ }
4269
+
4172
4270
  // src/campaign/worktree/index.ts
4173
4271
  import { execFileSync } from "child_process";
4174
- import { existsSync as existsSync3 } from "fs";
4272
+ import { existsSync as existsSync4 } from "fs";
4175
4273
  import { basename, isAbsolute as isAbsolute2, join as join5 } from "path";
4176
4274
  var WorktreeAdapterError = class extends Error {
4177
4275
  constructor(message, cause) {
@@ -4224,7 +4322,7 @@ function gitWorktreeAdapter(opts) {
4224
4322
  };
4225
4323
  }
4226
4324
  function resolveWorktreePath(surface, worktreeDir) {
4227
- if (isAbsolute2(surface.worktreeRef) && existsSync3(surface.worktreeRef)) return surface.worktreeRef;
4325
+ if (isAbsolute2(surface.worktreeRef) && existsSync4(surface.worktreeRef)) return surface.worktreeRef;
4228
4326
  if (worktreeDir) return join5(worktreeDir, basename(surface.worktreeRef));
4229
4327
  return surface.worktreeRef;
4230
4328
  }
@@ -4267,6 +4365,8 @@ export {
4267
4365
  neutralizationGate,
4268
4366
  sequentialPairedGate,
4269
4367
  sequentialDecide,
4368
+ rolloutArgumentDiff,
4369
+ classifyUngroundedLiterals,
4270
4370
  LabeledScenarioStoreError,
4271
4371
  FsLabeledScenarioStore,
4272
4372
  neutralizeText,
@@ -4299,8 +4399,10 @@ export {
4299
4399
  traceAnalystProposer,
4300
4400
  scoreDiscrimination,
4301
4401
  selectDiscriminative,
4402
+ acquireSingleRunLock,
4403
+ isTransientTransportFailure,
4302
4404
  WorktreeAdapterError,
4303
4405
  gitWorktreeAdapter,
4304
4406
  resolveWorktreePath
4305
4407
  };
4306
- //# sourceMappingURL=chunk-6SKVFBTR.js.map
4408
+ //# sourceMappingURL=chunk-R6D7NEYJ.js.map