@lazyingart/agintiflow 0.20.266 → 0.20.268

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lazyingart/agintiflow",
3
- "version": "0.20.266",
3
+ "version": "0.20.268",
4
4
  "type": "module",
5
5
  "description": "AgInTiFlow is a project-aware agent workspace for hybrid wet-dry R&D, hardware-aware intelligence, software automation, and industrial workflows.",
6
6
  "license": "Apache-2.0",
@@ -5306,6 +5306,159 @@ try {
5306
5306
  postMutationVerificationRuntime.testVerificationCommand === postMutationVerifier,
5307
5307
  "a material failed-test repair did not advance directly to its exact retained verifier"
5308
5308
  );
5309
+ const generatedDeckValidator =
5310
+ "python3 /tmp/presentation_deck_contract.py --root .";
5311
+ const staleGeneratedDeckState = {
5312
+ goal: [
5313
+ "Rebuild the canonical presentation output after repairing build_deck.py.",
5314
+ "Do not modify source_brief.md, measurements.csv,",
5315
+ "prompt.txt, or TASK.md.",
5316
+ `Run ${generatedDeckValidator} only after the generated deck is fresh.`,
5317
+ ].join("\n"),
5318
+ meta: {
5319
+ taskProfile: "slides",
5320
+ goalContract: {
5321
+ revision: 13,
5322
+ currentRequest: "Rebuild the canonical presentation output from build_deck.py.",
5323
+ },
5324
+ activeExecutionContract: {
5325
+ revision: 13,
5326
+ startedMutationRevision: 8,
5327
+ materialMutationRevision: 9,
5328
+ requiresFileMutation: true,
5329
+ requiresSourceGrounding: true,
5330
+ },
5331
+ projectVerification: {
5332
+ mutationRevision: 9,
5333
+ mutationHistory: [
5334
+ { revision: 8, toolName: "run_command", paths: [] },
5335
+ { revision: 9, toolName: "apply_patch", paths: ["build_deck.py"] },
5336
+ ],
5337
+ commandRuns: [{
5338
+ command:
5339
+ 'rm -rf dist && echo "removed dist" && python3 build_deck.py && ls -la output',
5340
+ at: "2026-08-27T18:18:14.726Z",
5341
+ ok: true,
5342
+ mutationRevision: 8,
5343
+ privateMutationRevision: 0,
5344
+ }],
5345
+ testRuns: [{
5346
+ command: generatedDeckValidator,
5347
+ at: "2026-08-27T18:24:28.347Z",
5348
+ mutationRevision: 9,
5349
+ privateMutationRevision: 0,
5350
+ passed: false,
5351
+ failureEvidenceVersion: 2,
5352
+ failureSignature: "stale-generated-deck",
5353
+ failureSummary: "acceptance failed: deck omits source-grounded phrase: single reader",
5354
+ }],
5355
+ },
5356
+ },
5357
+ };
5358
+ const staleGeneratedDeckRuntime = nextStepRuntimeConfig(
5359
+ {
5360
+ provider: "deepseek",
5361
+ taskProfile: "slides",
5362
+ commandCwd: workspace,
5363
+ goal: staleGeneratedDeckState.goal,
5364
+ },
5365
+ staleGeneratedDeckState
5366
+ );
5367
+ const staleGeneratedDeckPhase = buildKnownConstrainedPhasePlan(
5368
+ {
5369
+ provider: "deepseek",
5370
+ taskProfile: "slides",
5371
+ commandCwd: workspace,
5372
+ goal: staleGeneratedDeckState.goal,
5373
+ },
5374
+ staleGeneratedDeckState,
5375
+ staleGeneratedDeckRuntime
5376
+ );
5377
+ assert(
5378
+ staleGeneratedDeckRuntime.generatedArtifactProducerPending === true &&
5379
+ staleGeneratedDeckRuntime.generatedArtifactProducerCommand === "python3 build_deck.py" &&
5380
+ staleGeneratedDeckPhase?.mode === "generated-artifact-producer" &&
5381
+ staleGeneratedDeckPhase?.command === "python3 build_deck.py",
5382
+ `a stale generated artifact did not recover its exact safe producer before validation: ${JSON.stringify(
5383
+ staleGeneratedDeckRuntime
5384
+ )}`
5385
+ );
5386
+ recordProjectVerificationOutcome(
5387
+ staleGeneratedDeckState,
5388
+ {
5389
+ toolName: "run_command",
5390
+ ok: true,
5391
+ exitCode: 0,
5392
+ args: { command: "python3 build_deck.py" },
5393
+ stdout: "Wrote output/deck.pptx\n",
5394
+ stderr: "",
5395
+ commandPolicy: {
5396
+ category: "toolchain",
5397
+ writesWorkspace: true,
5398
+ mayMutateProject: false,
5399
+ substantiveTest: false,
5400
+ },
5401
+ },
5402
+ {
5403
+ provider: "deepseek",
5404
+ taskProfile: "slides",
5405
+ commandCwd: workspace,
5406
+ goal: staleGeneratedDeckState.goal,
5407
+ allowShellTool: true,
5408
+ sandboxMode: "host",
5409
+ }
5410
+ );
5411
+ const postProducerRuntime = nextStepRuntimeConfig(
5412
+ {
5413
+ provider: "deepseek",
5414
+ taskProfile: "slides",
5415
+ commandCwd: workspace,
5416
+ goal: staleGeneratedDeckState.goal,
5417
+ },
5418
+ staleGeneratedDeckState
5419
+ );
5420
+ assert(
5421
+ staleGeneratedDeckState.meta.projectVerification.mutationRevision === 10 &&
5422
+ postProducerRuntime.generatedArtifactProducerPending !== true &&
5423
+ postProducerRuntime.testVerificationPending === true &&
5424
+ postProducerRuntime.testVerificationCommand === generatedDeckValidator,
5425
+ `a successful producer replay did not advance exactly once to fresh validation: ${JSON.stringify({
5426
+ verification: staleGeneratedDeckState.meta.projectVerification,
5427
+ activeExecutionContract: staleGeneratedDeckState.meta.activeExecutionContract,
5428
+ runtime: postProducerRuntime,
5429
+ })}`
5430
+ );
5431
+ const immutableOnlyRepairState = {
5432
+ goal: "Treat service_ctl.py as immutable read-only source evidence and finish from existing results.",
5433
+ meta: {
5434
+ taskProfile: "devops",
5435
+ projectVerification: {
5436
+ mutationRevision: 0,
5437
+ mutationHistory: [],
5438
+ commandRuns: [],
5439
+ testRuns: [],
5440
+ },
5441
+ completionEvidenceRepair: {
5442
+ key: "protected-source-only",
5443
+ at: "2026-08-27T19:00:00.000Z",
5444
+ requiresFreshFileMutation: true,
5445
+ requiredFreshMutationRevision: 1,
5446
+ },
5447
+ toolLoop: { recent: [] },
5448
+ },
5449
+ };
5450
+ assert(
5451
+ nextStepRuntimeConfig(
5452
+ {
5453
+ provider: "deepseek",
5454
+ taskProfile: "devops",
5455
+ commandCwd: workspace,
5456
+ goal: immutableOnlyRepairState.goal,
5457
+ },
5458
+ immutableOnlyRepairState
5459
+ ).completionFreshMutationRequired !== true,
5460
+ "completion recovery forced a mutation when every concrete candidate was immutable"
5461
+ );
5309
5462
  const concreteGoalUpdate = applyContinuationContractTransition(
5310
5463
  concreteContinuationState,
5311
5464
  concreteContinuation,
@@ -1747,6 +1747,28 @@ sameNames(
1747
1747
  "failed-test repair did not receive the bounded diagnose-patch-retest tool surface"
1748
1748
  );
1749
1749
 
1750
+ const generatedArtifactProducerTools = selectProgressiveTools(allTools, {
1751
+ config: {
1752
+ provider: "localllm",
1753
+ testFailureRepairActive: true,
1754
+ testFailureRepairMutationRequired: true,
1755
+ generatedArtifactProducerPending: true,
1756
+ generatedArtifactProducerCommand: "python3 build_deck.py",
1757
+ },
1758
+ goal: "Rebuild the generated presentation before rerunning its validator.",
1759
+ profile: "slides",
1760
+ });
1761
+ sameNames(
1762
+ generatedArtifactProducerTools,
1763
+ ["run_command", "finish"],
1764
+ "a stale generated artifact did not expose only its retained producer command"
1765
+ );
1766
+ assertStrict.deepEqual(
1767
+ generatedArtifactProducerTools[0].function.parameters.properties.command.enum,
1768
+ ["python3 build_deck.py"],
1769
+ "the generated-artifact producer command was not schema-constrained"
1770
+ );
1771
+
1750
1772
  const mutationOnlyFailedTestRepairTools = selectProgressiveTools(allTools, {
1751
1773
  config: {
1752
1774
  provider: "localllm",
@@ -60,6 +60,16 @@ const coordinatedForbiddenOutputContract = deriveScsTaskContract({
60
60
  taskProfile: "devops",
61
61
  });
62
62
 
63
+ const wrappedImmutableSourceContract = deriveScsTaskContract({
64
+ goal: [
65
+ "Continue the exact task. Do not modify source_brief.md, measurements.csv,",
66
+ "prompt.txt, or TASK.md.",
67
+ "Treat source_brief.md, measurements.csv, prompt.txt, and TASK.md as immutable read-only source evidence.",
68
+ "Repair build_deck.py and rebuild output/deck.pptx.",
69
+ ].join("\n"),
70
+ taskProfile: "slides",
71
+ });
72
+
63
73
  const recoveryInstructionContract = deriveScsTaskContract({
64
74
  goal: [
65
75
  "Use the retained source and these two failures: the tests invoke ../service_ctl.py, while `python3 service_ctl.py start --state-dir .runtime` fails. Preserve the lifecycle assertions rather than replacing them, repair service_ctl.py, and remove the accidental untracked resume-after-git-baseline-recovery-dev-prompt.txt.",
@@ -152,6 +162,17 @@ assert.deepEqual(
152
162
  ["scratch.py", "temporary.py"],
153
163
  "a coordinated list did not retain each path governed by one exclusion"
154
164
  );
165
+ assert.deepEqual(
166
+ wrappedImmutableSourceContract.excludedOutputPaths.sort(),
167
+ ["TASK.md", "measurements.csv", "prompt.txt", "source_brief.md"].sort(),
168
+ "a wrapped immutable source list lost one or more protected paths"
169
+ );
170
+ assert(
171
+ !wrappedImmutableSourceContract.exactOutputPaths.some((item) =>
172
+ ["TASK.md", "measurements.csv", "prompt.txt", "source_brief.md"].includes(item)
173
+ ),
174
+ "an immutable source path leaked into exact output requirements"
175
+ );
155
176
  assert(
156
177
  recoveryInstructionContract.excludedOutputPaths.includes("resume-after-git-baseline-recovery-dev-prompt.txt") &&
157
178
  !recoveryInstructionContract.exactOutputPaths.includes("resume-after-git-baseline-recovery-dev-prompt.txt"),
@@ -2157,7 +2157,13 @@ export function buildKnownConstrainedPhasePlan(
2157
2157
  runtimeConfig = nextStepRuntimeConfig(config, state)
2158
2158
  ) {
2159
2159
  const repositoryStateRepair = runtimeConfig.testFailureRepositoryStateRepair === true;
2160
- if (runtimeConfig.testFailureRepairActive === true && !repositoryStateRepair) return null;
2160
+ const generatedArtifactProducer =
2161
+ runtimeConfig.generatedArtifactProducerPending === true;
2162
+ if (
2163
+ runtimeConfig.testFailureRepairActive === true &&
2164
+ !repositoryStateRepair &&
2165
+ !generatedArtifactProducer
2166
+ ) return null;
2161
2167
 
2162
2168
  const freshSourceMutation = runtimeConfig.completionFreshMutationRequired === true;
2163
2169
  const verificationPending = runtimeConfig.testVerificationPending === true;
@@ -2181,6 +2187,7 @@ export function buildKnownConstrainedPhasePlan(
2181
2187
  if (
2182
2188
  !repositoryStateRepair &&
2183
2189
  !freshSourceMutation &&
2190
+ !generatedArtifactProducer &&
2184
2191
  !verificationPending &&
2185
2192
  !requiredProjectCommandPending &&
2186
2193
  !verifiedCompletion &&
@@ -2191,19 +2198,22 @@ export function buildKnownConstrainedPhasePlan(
2191
2198
  }
2192
2199
 
2193
2200
  const command = String(
2194
- requiredProjectCommandPending
2195
- ? runtimeConfig.requiredProjectCommand || ""
2196
- : verificationPending
2197
- ? runtimeConfig.testVerificationCommand || ""
2198
- : repositoryStateRepair
2199
- ? runtimeConfig.testFailureCommand || ""
2200
- : runtimeConfig.verifiedCompletionCommand || ""
2201
+ generatedArtifactProducer
2202
+ ? runtimeConfig.generatedArtifactProducerCommand || ""
2203
+ : requiredProjectCommandPending
2204
+ ? runtimeConfig.requiredProjectCommand || ""
2205
+ : verificationPending
2206
+ ? runtimeConfig.testVerificationCommand || ""
2207
+ : repositoryStateRepair
2208
+ ? runtimeConfig.testFailureCommand || ""
2209
+ : runtimeConfig.verifiedCompletionCommand || ""
2201
2210
  ).trim();
2202
2211
  if (
2203
2212
  !verifiedCompletion &&
2204
2213
  !artifactCommitPending &&
2205
2214
  !taskOwnedCommitPending &&
2206
2215
  !freshSourceMutation &&
2216
+ !generatedArtifactProducer &&
2207
2217
  !command
2208
2218
  ) return null;
2209
2219
 
@@ -2211,6 +2221,8 @@ export function buildKnownConstrainedPhasePlan(
2211
2221
  ? "repository-state-repair"
2212
2222
  : freshSourceMutation
2213
2223
  ? "fresh-source-mutation"
2224
+ : generatedArtifactProducer
2225
+ ? "generated-artifact-producer"
2214
2226
  : requiredProjectCommandPending
2215
2227
  ? "required-project-command"
2216
2228
  : verificationPending
@@ -2250,6 +2262,12 @@ export function buildKnownConstrainedPhasePlan(
2250
2262
  "2. Preserve unrelated current behavior and do not edit private verification evidence.",
2251
2263
  "3. After the mutation succeeds, rerun the retained validation and complete required Git actions.",
2252
2264
  ].join("\n")
2265
+ : generatedArtifactProducer
2266
+ ? [
2267
+ `1. Run the exact retained local producer command now: ${command}`,
2268
+ "2. Rebuild generated artifacts from the latest canonical source mutation; do not rerun the stale validator first or substitute another command.",
2269
+ "3. After the producer succeeds, run the exact retained validator and repair only from any fresh concrete failure.",
2270
+ ].join("\n")
2253
2271
  : artifactCommitPending || taskOwnedCommitPending
2254
2272
  ? [
2255
2273
  "1. Use the offered commit_project_changes tool once; its path scope comes from recorded task-owned mutations.",
@@ -2281,6 +2299,8 @@ export function buildKnownConstrainedPhasePlan(
2281
2299
  ? runtimeConfig.completionFreshMutationNeedsSourceRead === true
2282
2300
  ? "Completion was rejected because a fresh canonical source correction is still missing. Read one exact offered project file now; command, test, Git, and finish actions remain intentionally unavailable until the source is grounded and materially patched."
2283
2301
  : "Completion was rejected because a fresh canonical source correction is still missing. Use the offered path-bounded apply_patch tool now. Do not substitute another read-only inspection, test rerun, Git command, private verifier edit, or finish claim."
2302
+ : generatedArtifactProducer
2303
+ ? "A canonical producer source changed after the last successful build. Run only the exact retained local producer command now so validation observes fresh artifacts; do not rerun the stale validator or invent another source edit."
2284
2304
  : artifactCommitPending
2285
2305
  ? "The exact artifact and current source changes already passed deterministic checks. Only the required local commit is missing. Call commit_project_changes with a concise factual subject, then finish; do not restart discovery or validation."
2286
2306
  : taskOwnedCommitPending
@@ -6025,10 +6045,14 @@ export function recordProjectVerificationOutcome(state = {}, toolResult = {}, co
6025
6045
  // verification regardless of its final exit status. Test identity and
6026
6046
  // mutation capability are independent: a generator or snapshot-updating
6027
6047
  // test still advances the revision, then records its evidence there.
6048
+ const generatedArtifactProducer = safeProjectProducerSegment(command, config);
6028
6049
  const projectContentMutation = Boolean(
6029
6050
  command &&
6030
6051
  toolResult.blocked !== true &&
6031
- commandCanMutateProjectContent(mutationCommand, commandPolicy)
6052
+ (
6053
+ commandCanMutateProjectContent(mutationCommand, commandPolicy) ||
6054
+ generatedArtifactProducer
6055
+ )
6032
6056
  );
6033
6057
  let requiredBatch = currentRequiredCommandBatch(verification, requiredCommands);
6034
6058
  const activeExecutionContract = state.meta?.activeExecutionContract;
@@ -6086,6 +6110,21 @@ export function recordProjectVerificationOutcome(state = {}, toolResult = {}, co
6086
6110
  paths: [],
6087
6111
  commandCategory: String(commandPolicy.category || "general-shell"),
6088
6112
  }, config);
6113
+ if (
6114
+ generatedArtifactProducer &&
6115
+ Number(activeExecutionContract?.revision || 0) ===
6116
+ Number(state.meta?.goalContract?.revision || 0)
6117
+ ) {
6118
+ activeExecutionContract.materialMutationRevision = verification.mutationRevision;
6119
+ activeExecutionContract.materialMutationCommands = [
6120
+ ...new Set([
6121
+ ...(Array.isArray(activeExecutionContract.materialMutationCommands)
6122
+ ? activeExecutionContract.materialMutationCommands
6123
+ : []),
6124
+ generatedArtifactProducer,
6125
+ ]),
6126
+ ].slice(0, 12);
6127
+ }
6089
6128
  }
6090
6129
  const run = {
6091
6130
  command,
@@ -6096,6 +6135,7 @@ export function recordProjectVerificationOutcome(state = {}, toolResult = {}, co
6096
6135
  ...(requiredBatch?.id ? { requiredCommandBatchId: requiredBatch.id } : {}),
6097
6136
  ...(requiredCommand ? { requiredProjectCommand: requiredCommand } : {}),
6098
6137
  ...(exitProbe.present ? { explicitExitStatus: exitProbe.status } : {}),
6138
+ ...(generatedArtifactProducer ? { generatedArtifactProducer } : {}),
6099
6139
  };
6100
6140
  if (requiredCommand && commandSucceeded) {
6101
6141
  if (!requiredBatch && requiredMutatingCommands.length === 0) {
@@ -10415,6 +10455,139 @@ function completionFreshMutationCandidatePaths(state = {}, config = {}) {
10415
10455
  return selected.slice(0, 16);
10416
10456
  }
10417
10457
 
10458
+ function commandSegmentHasProducerIntent(command = "") {
10459
+ const normalized = normalizeProjectCommand(command);
10460
+ const tokens = tokenizeShellWords(normalized);
10461
+ if (!tokens.length) return false;
10462
+ let index = 0;
10463
+ while (/^[A-Za-z_][A-Za-z0-9_]*=/.test(String(tokens[index] || ""))) {
10464
+ index += 1;
10465
+ }
10466
+ const executable = path.posix.basename(
10467
+ String(tokens[index] || "").replace(/\\/g, "/")
10468
+ ).toLocaleLowerCase("en-US");
10469
+ const args = tokens.slice(index + 1);
10470
+ const rejectedProducerName =
10471
+ /(?:^|[_-])(?:acceptance|audit|check|lint|smoke|spec|test|validat(?:e|or|ion)?|verif(?:y|ier|ication)?)(?:[_-]|$)/i;
10472
+ const producerName =
10473
+ /(?:^|[_-])(?:build|bundle|compile|deck|export|generat(?:e|or)|package|presentation|regen(?:erate)?|render|report|slides?)(?:[_-]|$)/i;
10474
+
10475
+ if (["python", "python3", "node", "ruby", "bash", "sh"].some((name) =>
10476
+ executable === name || executable.startsWith(`${name}.`)
10477
+ )) {
10478
+ const scriptIndex = args[0] === "-m" ? 1 : 0;
10479
+ const scriptName = path.posix.basename(
10480
+ String(args[scriptIndex] || "").replace(/\\/g, "/")
10481
+ ).replace(/\.[A-Za-z0-9]{1,8}$/u, "");
10482
+ return Boolean(
10483
+ scriptName &&
10484
+ producerName.test(scriptName) &&
10485
+ !rejectedProducerName.test(scriptName)
10486
+ );
10487
+ }
10488
+
10489
+ if (["npm", "pnpm", "yarn", "bun"].includes(executable)) {
10490
+ const script = String(
10491
+ args[0] === "run" ? args[1] : args[0]
10492
+ ).toLocaleLowerCase("en-US");
10493
+ return Boolean(
10494
+ script && producerName.test(script) && !rejectedProducerName.test(script)
10495
+ );
10496
+ }
10497
+ if (["make", "ninja", "latexmk", "pdflatex", "xelatex", "lualatex", "openscad"].includes(executable)) {
10498
+ return true;
10499
+ }
10500
+ if (executable === "pandoc") return args.some((arg) => ["-o", "--output"].includes(arg));
10501
+ if (executable === "typst") return args[0] === "compile";
10502
+ if (executable === "cmake") return args.includes("--build");
10503
+ if (executable === "meson") return ["compile", "install"].includes(args[0]);
10504
+ if (["cargo", "go", "dotnet"].includes(executable)) return args[0] === "build";
10505
+ return Boolean(
10506
+ executable &&
10507
+ producerName.test(executable.replace(/\.[A-Za-z0-9]{1,8}$/u, "")) &&
10508
+ !rejectedProducerName.test(executable)
10509
+ );
10510
+ }
10511
+
10512
+ function safeProjectProducerSegment(command = "", config = {}) {
10513
+ const normalized = normalizeProjectCommand(
10514
+ normalizeCommandForPolicy(command, config)
10515
+ );
10516
+ const unwrapped = parseNonMutatingExitStatusWrapper(normalized)?.command || normalized;
10517
+ const sequence = parseTopLevelShellSequence(unwrapped);
10518
+ if (
10519
+ !sequence.commands.length ||
10520
+ sequence.openQuote ||
10521
+ sequence.trailingEscape ||
10522
+ sequence.trailingSeparator
10523
+ ) {
10524
+ return "";
10525
+ }
10526
+ for (const rawSegment of sequence.commands) {
10527
+ const segment = normalizeProjectCommand(rawSegment);
10528
+ if (!segment || !commandSegmentHasProducerIntent(segment)) continue;
10529
+ const policy = classifyCommand(segment);
10530
+ if (
10531
+ policy.hardBlocked === true ||
10532
+ policy.needsNetwork === true ||
10533
+ ["blocked", "destructive", "external-write", "git-remote", "git-workflow", "package-install"].includes(
10534
+ String(policy.category || "")
10535
+ ) ||
10536
+ isSubstantiveTestCommand(segment, config) ||
10537
+ !commandCanMutateProjectContent(segment, policy)
10538
+ ) {
10539
+ continue;
10540
+ }
10541
+ return segment;
10542
+ }
10543
+ return "";
10544
+ }
10545
+
10546
+ function pendingGeneratedArtifactProducerCommand(
10547
+ state = {},
10548
+ config = {},
10549
+ verification = {},
10550
+ currentFailedTest = null
10551
+ ) {
10552
+ if (!currentFailedTest || currentFailedTest.passed === true) return "";
10553
+ if (failedTestRequiresCleanRepositoryState(currentFailedTest)) return "";
10554
+ const context = [
10555
+ completionContractGoal(config, state),
10556
+ state.meta?.taskProfile || config.taskProfile || "",
10557
+ currentFailedTest.failureSummary || "",
10558
+ ].join("\n");
10559
+ if (
10560
+ !/(?:\b(?:artifact|build|bundle|compile|deck|export|generat(?:e|ed|or)|output|package|presentation|rebuild|regenerate|render|report|slides?)\b|\.(?:pdf|pptx|docx|html|svg|png|jpe?g|webp|mp4|mov)\b)/i.test(
10561
+ context
10562
+ )
10563
+ ) {
10564
+ return "";
10565
+ }
10566
+ const mutationRevision = Math.max(0, Number(verification.mutationRevision || 0));
10567
+ const latestSourceMutation = [...(verification.mutationHistory || [])]
10568
+ .reverse()
10569
+ .find(
10570
+ (mutation) =>
10571
+ Number(mutation?.revision || 0) === mutationRevision &&
10572
+ ["apply_patch", "write_file"].includes(String(mutation?.toolName || "")) &&
10573
+ (Array.isArray(mutation?.paths) ? mutation.paths : []).some(
10574
+ (item) => !isPrivateVerificationEvidencePath(item)
10575
+ )
10576
+ );
10577
+ if (!latestSourceMutation) return "";
10578
+ for (const run of [...(verification.commandRuns || [])].reverse()) {
10579
+ if (
10580
+ run?.ok !== true ||
10581
+ Number(run?.mutationRevision || 0) >= mutationRevision
10582
+ ) {
10583
+ continue;
10584
+ }
10585
+ const producer = safeProjectProducerSegment(run?.command || "", config);
10586
+ if (producer) return producer;
10587
+ }
10588
+ return "";
10589
+ }
10590
+
10418
10591
  function exactOutputPathsForState(state = {}) {
10419
10592
  const scsOutputPaths = Array.isArray(state.meta?.scs?.taskContract?.exactOutputPaths)
10420
10593
  ? state.meta.scs.taskContract.exactOutputPaths.filter(Boolean)
@@ -11082,7 +11255,7 @@ export function nextStepRuntimeConfig(config = {}, state = {}) {
11082
11255
  const entryAt = Date.parse(String(entry?.at || ""));
11083
11256
  return !Number.isFinite(repairAt) || (Number.isFinite(entryAt) && entryAt > repairAt);
11084
11257
  });
11085
- if (candidatePaths.length > 0 || !currentTurnRequiresFreshMutation) {
11258
+ if (candidatePaths.length > 0) {
11086
11259
  runtimeConfig.completionFreshMutationRequired = true;
11087
11260
  runtimeConfig.completionFreshMutationRevision = currentTurnRequiresFreshMutation
11088
11261
  ? groundingMutationBaseline + 1
@@ -11099,6 +11272,15 @@ export function nextStepRuntimeConfig(config = {}, state = {}) {
11099
11272
  const latestRecordedTest = [...testRuns]
11100
11273
  .reverse()
11101
11274
  .find((run) => String(run?.command || "").trim());
11275
+ const freshGeneratedArtifactProducer = [...(verification.commandRuns || [])]
11276
+ .reverse()
11277
+ .some(
11278
+ (run) =>
11279
+ run?.ok === true &&
11280
+ String(run?.generatedArtifactProducer || "").trim() &&
11281
+ Number(run?.mutationRevision || 0) === mutationRevision &&
11282
+ Number(run?.privateMutationRevision || 0) === privateMutationRevision
11283
+ );
11102
11284
  const retainedRepairPacket = state.meta?.failedTestRecoveryPacket;
11103
11285
  const repairedRetainedFailure = Boolean(
11104
11286
  latestRecordedTest?.passed !== true &&
@@ -11112,6 +11294,16 @@ export function nextStepRuntimeConfig(config = {}, state = {}) {
11112
11294
  );
11113
11295
  const retainedFailedTest =
11114
11296
  latestCurrentTest && latestCurrentTest.passed !== true ? latestCurrentTest : null;
11297
+ const pendingArtifactProducerCommand = pendingGeneratedArtifactProducerCommand(
11298
+ state,
11299
+ config,
11300
+ verification,
11301
+ retainedFailedTest
11302
+ );
11303
+ if (pendingArtifactProducerCommand) {
11304
+ runtimeConfig.generatedArtifactProducerPending = true;
11305
+ runtimeConfig.generatedArtifactProducerCommand = pendingArtifactProducerCommand;
11306
+ }
11115
11307
  if (retainedFailedTest) {
11116
11308
  const repositoryStateRepairMarker = state.meta?.repositoryStateRepair;
11117
11309
  const retainedRepositoryStateRepair = Boolean(
@@ -11572,7 +11764,7 @@ export function nextStepRuntimeConfig(config = {}, state = {}) {
11572
11764
  runtimeConfig.testVerificationCommand = String(retainedFailedTest.command || "");
11573
11765
  }
11574
11766
  } else if (
11575
- (!implementationOpen || repairedRetainedFailure) &&
11767
+ (!implementationOpen || repairedRetainedFailure || freshGeneratedArtifactProducer) &&
11576
11768
  !latestCurrentTest &&
11577
11769
  latestRecordedTest &&
11578
11770
  !testRunMatchesVerificationRevision(latestRecordedTest, verification)
@@ -14710,7 +14902,9 @@ async function executeTool(browserState, toolCall, snapshot, config, store, obse
14710
14902
  packageInstallPolicy: policy.packageInstallPolicy,
14711
14903
  needsNetwork: Boolean(policy.needsNetwork),
14712
14904
  writesWorkspace: Boolean(policy.writesWorkspace),
14713
- mayMutateProject: Boolean(policy.mayMutateProject),
14905
+ ...(typeof policy.mayMutateProject === "boolean"
14906
+ ? { mayMutateProject: policy.mayMutateProject }
14907
+ : {}),
14714
14908
  substantiveTest: Boolean(policy.substantiveTest),
14715
14909
  gitOnly: Boolean(policy.gitOnly),
14716
14910
  noMatchExitIsSuccess: Boolean(policy.noMatchExitIsSuccess),
@@ -1937,6 +1937,16 @@ export function selectProgressiveTools(
1937
1937
  return artifactValidationToolNames(config).map((name) => available.get(name)).filter(Boolean);
1938
1938
  }
1939
1939
 
1940
+ if (config.generatedArtifactProducerPending === true) {
1941
+ const available = new Map(enabled.map(({ name, tool }) => [name, tool]));
1942
+ const producerCommand = constrainRunCommand(
1943
+ available.get("run_command"),
1944
+ config.generatedArtifactProducerCommand,
1945
+ "Run this exact previously successful local producer command once. Canonical source changed after its last run, so generated artifacts must be rebuilt before the retained validator can provide fresh evidence. Do not substitute another command or rerun the stale validator first."
1946
+ );
1947
+ return [producerCommand, finish].filter(Boolean);
1948
+ }
1949
+
1940
1950
  if (config.testFailureRepairActive === true) {
1941
1951
  const available = new Map(enabled.map(({ name, tool }) => [name, tool]));
1942
1952
  if (
@@ -542,7 +542,10 @@ export function filterExplicitlyExcludedOutputPaths(paths = [], exclusions = [])
542
542
  }
543
543
 
544
544
  export function inferExplicitlyExcludedOutputPaths(goal = "") {
545
- const source = String(goal || "");
545
+ // Preserve coordinated path lists that wrap after a comma. Prompt and task
546
+ // files commonly format "do not modify a, b,\nc, or d" across lines; splitting
547
+ // that text first drops the governing negative action from the continuation.
548
+ const source = String(goal || "").replace(/([,,、])\s*\r?\n\s*/gu, "$1 ");
546
549
  if (!source.trim()) return [];
547
550
  const extensionPattern = "md|txt|json|jsonl|ndjson|ya?ml|html|css|js|ts|tsx|jsx|py|sh|csv|tex|svg|png|jpe?g|webp|mp4|mov|pdf|docx";
548
551
  const pathPattern = new RegExp(
@@ -573,6 +576,11 @@ export function inferExplicitlyExcludedOutputPaths(goal = "") {
573
576
  for (const clause of source.split(/[;;\n]|(?<=[.!?。!?])\s+/u)) {
574
577
  pathPattern.lastIndex = 0;
575
578
  const matches = [...clause.matchAll(pathPattern)];
579
+ const immutablePathClause = Boolean(
580
+ /\b(?:treat|consider|regard)\b[^!?。!?;;\n]{0,260}\b(?:as\s+)?(?:immutable|read[ -]?only)\b/i.test(
581
+ clause
582
+ )
583
+ );
576
584
  let previousExcluded = false;
577
585
  for (let matchIndex = 0; matchIndex < matches.length; matchIndex += 1) {
578
586
  const match = matches[matchIndex];
@@ -595,6 +603,7 @@ export function inferExplicitlyExcludedOutputPaths(goal = "") {
595
603
  )
596
604
  );
597
605
  const directExclusion = Boolean(
606
+ immutablePathClause ||
598
607
  negativeActionBefore.test(before) ||
599
608
  negativeActionAfter.test(after) ||
600
609
  keepAbsent.test(`${before}${after}`) ||