@lazyingart/agintiflow 0.20.271 → 0.20.273
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 +1 -1
- package/scripts/smoke-dynamic-step-budget.js +106 -1
- package/scripts/smoke-progressive-tool-selection.js +22 -0
- package/scripts/smoke-scs-evidence-visibility.js +28 -0
- package/src/agent-runner.js +179 -12
- package/src/progressive-tool-selection.js +26 -10
- package/src/scs-evidence.js +16 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lazyingart/agintiflow",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.273",
|
|
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,8 +5306,19 @@ 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 generatedDeckValidatorPath = path.join(
|
|
5310
|
+
tempRoot,
|
|
5311
|
+
"acceptance",
|
|
5312
|
+
"presentation_deck_contract.py"
|
|
5313
|
+
);
|
|
5314
|
+
await fs.mkdir(path.dirname(generatedDeckValidatorPath), { recursive: true });
|
|
5315
|
+
await fs.writeFile(
|
|
5316
|
+
generatedDeckValidatorPath,
|
|
5317
|
+
"raise SystemExit('acceptance fixture')\n",
|
|
5318
|
+
"utf8"
|
|
5319
|
+
);
|
|
5309
5320
|
const generatedDeckValidator =
|
|
5310
|
-
|
|
5321
|
+
`python3 ${generatedDeckValidatorPath} --root .`;
|
|
5311
5322
|
await fs.writeFile(
|
|
5312
5323
|
path.join(workspace, "build_deck.py"),
|
|
5313
5324
|
"print('build canonical deck')\n",
|
|
@@ -5485,6 +5496,100 @@ try {
|
|
|
5485
5496
|
runtime: postProducerRuntime,
|
|
5486
5497
|
})}`
|
|
5487
5498
|
);
|
|
5499
|
+
const failedAfterProducerState = structuredClone(staleGeneratedDeckState);
|
|
5500
|
+
failedAfterProducerState.meta.goalContract.taskGoal = failedAfterProducerState.goal;
|
|
5501
|
+
failedAfterProducerState.meta.projectVerification.mutationHistory.splice(1, 0, {
|
|
5502
|
+
revision: 8,
|
|
5503
|
+
toolName: "apply_patch",
|
|
5504
|
+
paths: ["TASK.md"],
|
|
5505
|
+
});
|
|
5506
|
+
failedAfterProducerState.meta.projectVerification.testRuns.push({
|
|
5507
|
+
command: generatedDeckValidator,
|
|
5508
|
+
at: "2026-08-27T19:05:00.000Z",
|
|
5509
|
+
mutationRevision: 10,
|
|
5510
|
+
privateMutationRevision: 0,
|
|
5511
|
+
passed: false,
|
|
5512
|
+
failureEvidenceVersion: 2,
|
|
5513
|
+
failureSignature: "fresh-generated-deck-visible-text",
|
|
5514
|
+
failureSummary: "acceptance failed: deck omits source-grounded phrase: single reader",
|
|
5515
|
+
});
|
|
5516
|
+
await fs.writeFile(
|
|
5517
|
+
path.join(workspace, "TASK.md"),
|
|
5518
|
+
"Treat source_brief.md, measurements.csv, prompt.txt, and TASK.md as immutable.\n",
|
|
5519
|
+
"utf8"
|
|
5520
|
+
);
|
|
5521
|
+
const failedAfterProducerPacket = await buildFailedTestRecoveryPacket(
|
|
5522
|
+
{
|
|
5523
|
+
provider: "deepseek",
|
|
5524
|
+
taskProfile: "slides",
|
|
5525
|
+
commandCwd: workspace,
|
|
5526
|
+
goal: failedAfterProducerState.goal,
|
|
5527
|
+
},
|
|
5528
|
+
failedAfterProducerState
|
|
5529
|
+
);
|
|
5530
|
+
assert(
|
|
5531
|
+
JSON.stringify(failedAfterProducerPacket.repairPaths) ===
|
|
5532
|
+
JSON.stringify(["build_deck.py"]),
|
|
5533
|
+
"a fresh generated-artifact failure dropped its latest mutable producer or retained an explicitly immutable input"
|
|
5534
|
+
);
|
|
5535
|
+
failedAfterProducerState.meta.failedTestRecoveryPacket = {
|
|
5536
|
+
packetVersion: 15,
|
|
5537
|
+
content: failedAfterProducerPacket.content,
|
|
5538
|
+
paths: failedAfterProducerPacket.paths,
|
|
5539
|
+
repairPaths: failedAfterProducerPacket.repairPaths,
|
|
5540
|
+
mutationRevision: 10,
|
|
5541
|
+
failureSignature: "fresh-generated-deck-visible-text",
|
|
5542
|
+
generatedAt: "2026-08-27T19:05:01.000Z",
|
|
5543
|
+
};
|
|
5544
|
+
const failedAfterProducerRuntime = nextStepRuntimeConfig(
|
|
5545
|
+
{
|
|
5546
|
+
provider: "deepseek",
|
|
5547
|
+
taskProfile: "slides",
|
|
5548
|
+
commandCwd: workspace,
|
|
5549
|
+
goal: failedAfterProducerState.goal,
|
|
5550
|
+
},
|
|
5551
|
+
failedAfterProducerState
|
|
5552
|
+
);
|
|
5553
|
+
assert(
|
|
5554
|
+
JSON.stringify(failedAfterProducerRuntime.testFailureRepairContextPaths) ===
|
|
5555
|
+
JSON.stringify(["build_deck.py"]),
|
|
5556
|
+
"failed-test recovery forced immutable evidence reads instead of grounding the canonical producer"
|
|
5557
|
+
);
|
|
5558
|
+
assert(
|
|
5559
|
+
JSON.stringify(failedAfterProducerRuntime.testFailureDiagnosticReadPaths) ===
|
|
5560
|
+
JSON.stringify([generatedDeckValidatorPath]) &&
|
|
5561
|
+
failedAfterProducerRuntime.readOnlyRoots.includes(
|
|
5562
|
+
path.dirname(generatedDeckValidatorPath)
|
|
5563
|
+
),
|
|
5564
|
+
"an exact external validator from the retained failed command was not exposed through a narrow read-only root"
|
|
5565
|
+
);
|
|
5566
|
+
const consumedExternalValidatorState = structuredClone(failedAfterProducerState);
|
|
5567
|
+
consumedExternalValidatorState.meta.toolLoop =
|
|
5568
|
+
consumedExternalValidatorState.meta.toolLoop || { recent: [] };
|
|
5569
|
+
consumedExternalValidatorState.meta.toolLoop.recent = [
|
|
5570
|
+
...(consumedExternalValidatorState.meta.toolLoop.recent || []),
|
|
5571
|
+
{
|
|
5572
|
+
toolName: "read_file",
|
|
5573
|
+
path: generatedDeckValidatorPath,
|
|
5574
|
+
ok: true,
|
|
5575
|
+
blocked: false,
|
|
5576
|
+
goalRevision: 13,
|
|
5577
|
+
at: "2026-08-27T19:05:02.000Z",
|
|
5578
|
+
},
|
|
5579
|
+
];
|
|
5580
|
+
const consumedExternalValidatorRuntime = nextStepRuntimeConfig(
|
|
5581
|
+
{
|
|
5582
|
+
provider: "deepseek",
|
|
5583
|
+
taskProfile: "slides",
|
|
5584
|
+
commandCwd: workspace,
|
|
5585
|
+
goal: consumedExternalValidatorState.goal,
|
|
5586
|
+
},
|
|
5587
|
+
consumedExternalValidatorState
|
|
5588
|
+
);
|
|
5589
|
+
assert(
|
|
5590
|
+
consumedExternalValidatorRuntime.testFailureDiagnosticReadPaths.length === 0,
|
|
5591
|
+
"an exact external validator remained exposed after its bounded read completed"
|
|
5592
|
+
);
|
|
5488
5593
|
const immutableOnlyRepairState = {
|
|
5489
5594
|
goal: "Treat service_ctl.py as immutable read-only source evidence and finish from existing results.",
|
|
5490
5595
|
meta: {
|
|
@@ -1804,6 +1804,28 @@ sameNames(
|
|
|
1804
1804
|
"an unchanged failed-test rerun did not close discovery until a real mutation"
|
|
1805
1805
|
);
|
|
1806
1806
|
|
|
1807
|
+
const externalValidatorPath = "/tmp/aginti-acceptance/deck_contract.py";
|
|
1808
|
+
const externalDiagnosticFailedTestRepairTools = selectProgressiveTools(allTools, {
|
|
1809
|
+
config: {
|
|
1810
|
+
provider: "deepseek",
|
|
1811
|
+
testFailureRepairActive: true,
|
|
1812
|
+
testFailureRepairMutationRequired: true,
|
|
1813
|
+
testFailureDiagnosticReadPaths: [externalValidatorPath],
|
|
1814
|
+
},
|
|
1815
|
+
goal: "Repair the canonical producer from the exact external acceptance contract.",
|
|
1816
|
+
profile: "slides",
|
|
1817
|
+
});
|
|
1818
|
+
sameNames(
|
|
1819
|
+
externalDiagnosticFailedTestRepairTools,
|
|
1820
|
+
["read_file", "apply_patch", "finish"],
|
|
1821
|
+
"a retained external validator was not exposed as one bounded read during mutation-only recovery"
|
|
1822
|
+
);
|
|
1823
|
+
assertStrict.deepEqual(
|
|
1824
|
+
externalDiagnosticFailedTestRepairTools[0].function.parameters.properties.path.enum,
|
|
1825
|
+
[externalValidatorPath],
|
|
1826
|
+
"the external validator read was not schema-constrained to its exact path"
|
|
1827
|
+
);
|
|
1828
|
+
|
|
1807
1829
|
const failedTestPatchContextTools = selectProgressiveTools(allTools, {
|
|
1808
1830
|
config: {
|
|
1809
1831
|
provider: "localllm",
|
|
@@ -70,6 +70,24 @@ const wrappedImmutableSourceContract = deriveScsTaskContract({
|
|
|
70
70
|
taskProfile: "slides",
|
|
71
71
|
});
|
|
72
72
|
|
|
73
|
+
const actionWrappedImmutableSourceContract = deriveScsTaskContract({
|
|
74
|
+
goal: [
|
|
75
|
+
"Continue the exact task. Do not",
|
|
76
|
+
"modify source_brief.md, measurements.csv, prompt.txt, or TASK.md.",
|
|
77
|
+
"Repair build_deck.py and rebuild output/deck.pptx.",
|
|
78
|
+
].join("\n"),
|
|
79
|
+
taskProfile: "slides",
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const pathWrappedImmutableSourceContract = deriveScsTaskContract({
|
|
83
|
+
goal: [
|
|
84
|
+
"Continue the exact task. Do not modify",
|
|
85
|
+
"source_brief.md, measurements.csv, prompt.txt, or TASK.md.",
|
|
86
|
+
"Repair build_deck.py and rebuild output/deck.pptx.",
|
|
87
|
+
].join("\n"),
|
|
88
|
+
taskProfile: "slides",
|
|
89
|
+
});
|
|
90
|
+
|
|
73
91
|
const recoveryInstructionContract = deriveScsTaskContract({
|
|
74
92
|
goal: [
|
|
75
93
|
"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.",
|
|
@@ -173,6 +191,16 @@ assert(
|
|
|
173
191
|
),
|
|
174
192
|
"an immutable source path leaked into exact output requirements"
|
|
175
193
|
);
|
|
194
|
+
for (const contract of [
|
|
195
|
+
actionWrappedImmutableSourceContract,
|
|
196
|
+
pathWrappedImmutableSourceContract,
|
|
197
|
+
]) {
|
|
198
|
+
assert.deepEqual(
|
|
199
|
+
contract.excludedOutputPaths.sort(),
|
|
200
|
+
["TASK.md", "measurements.csv", "prompt.txt", "source_brief.md"].sort(),
|
|
201
|
+
"a negative action or its governed path list lost protection across a line wrap"
|
|
202
|
+
);
|
|
203
|
+
}
|
|
176
204
|
assert(
|
|
177
205
|
recoveryInstructionContract.excludedOutputPaths.includes("resume-after-git-baseline-recovery-dev-prompt.txt") &&
|
|
178
206
|
!recoveryInstructionContract.exactOutputPaths.includes("resume-after-git-baseline-recovery-dev-prompt.txt"),
|
package/src/agent-runner.js
CHANGED
|
@@ -4085,6 +4085,7 @@ async function applyContinuationPrompt(state, config, observers) {
|
|
|
4085
4085
|
packetVersion: FAILED_TEST_RECOVERY_PACKET_VERSION,
|
|
4086
4086
|
content: retainedTestEvidence.content,
|
|
4087
4087
|
paths: retainedTestEvidence.paths,
|
|
4088
|
+
repairPaths: retainedTestEvidence.repairPaths,
|
|
4088
4089
|
mutationRevision: Number(currentFailure?.mutationRevision || 0),
|
|
4089
4090
|
failureSignature: String(currentFailure?.failureSignature || ""),
|
|
4090
4091
|
command: String(currentFailure?.command || ""),
|
|
@@ -6624,6 +6625,109 @@ function safeRecoveryEvidencePath(value = "") {
|
|
|
6624
6625
|
return PLAIN_TEXT_FILE_EXTENSIONS.has(path.extname(candidate).toLowerCase()) ? candidate : "";
|
|
6625
6626
|
}
|
|
6626
6627
|
|
|
6628
|
+
function failedTestMutationRepairPaths(
|
|
6629
|
+
config = {},
|
|
6630
|
+
state = {},
|
|
6631
|
+
testRun = {},
|
|
6632
|
+
excludedPaths = []
|
|
6633
|
+
) {
|
|
6634
|
+
const verification = state.meta?.projectVerification || {};
|
|
6635
|
+
const history = Array.isArray(verification.mutationHistory)
|
|
6636
|
+
? verification.mutationHistory
|
|
6637
|
+
: verification.lastMutation
|
|
6638
|
+
? [verification.lastMutation]
|
|
6639
|
+
: [];
|
|
6640
|
+
const maximumRevision = Math.max(
|
|
6641
|
+
0,
|
|
6642
|
+
Number(testRun?.mutationRevision ?? verification.mutationRevision ?? 0)
|
|
6643
|
+
);
|
|
6644
|
+
const taskGoal = String(
|
|
6645
|
+
state.meta?.goalContract?.taskGoal || state.goal || config.goal || ""
|
|
6646
|
+
).trim();
|
|
6647
|
+
const activeTaskHash = taskGoal ? hashForLog(taskGoal) : "";
|
|
6648
|
+
const repairPaths = [];
|
|
6649
|
+
for (const mutation of [...history].reverse()) {
|
|
6650
|
+
if (
|
|
6651
|
+
Number(mutation?.revision || 0) > maximumRevision ||
|
|
6652
|
+
!["apply_patch", "write_file"].includes(String(mutation?.toolName || "")) ||
|
|
6653
|
+
(activeTaskHash && mutation?.taskHash && mutation.taskHash !== activeTaskHash)
|
|
6654
|
+
) {
|
|
6655
|
+
continue;
|
|
6656
|
+
}
|
|
6657
|
+
for (const candidate of Array.isArray(mutation?.paths) ? mutation.paths : []) {
|
|
6658
|
+
const safePath = safeRecoveryEvidencePath(candidate);
|
|
6659
|
+
if (
|
|
6660
|
+
!safePath ||
|
|
6661
|
+
pathLooksLikeTestSource(safePath) ||
|
|
6662
|
+
isPrivateVerificationEvidencePath(safePath) ||
|
|
6663
|
+
filterExplicitlyExcludedOutputPaths([safePath], excludedPaths).length === 0 ||
|
|
6664
|
+
repairPaths.includes(safePath)
|
|
6665
|
+
) {
|
|
6666
|
+
continue;
|
|
6667
|
+
}
|
|
6668
|
+
repairPaths.push(safePath);
|
|
6669
|
+
if (repairPaths.length >= 6) return repairPaths;
|
|
6670
|
+
}
|
|
6671
|
+
}
|
|
6672
|
+
return repairPaths;
|
|
6673
|
+
}
|
|
6674
|
+
|
|
6675
|
+
function failedTestCanonicalRepairPaths(state = {}) {
|
|
6676
|
+
const packet = state.meta?.failedTestRecoveryPacket || {};
|
|
6677
|
+
const preferred = Array.isArray(packet.repairPaths) && packet.repairPaths.length
|
|
6678
|
+
? packet.repairPaths
|
|
6679
|
+
: packet.paths;
|
|
6680
|
+
return (Array.isArray(preferred) ? preferred : [])
|
|
6681
|
+
.map(safeRecoveryEvidencePath)
|
|
6682
|
+
.filter(Boolean)
|
|
6683
|
+
.filter((item, index, items) => items.indexOf(item) === index);
|
|
6684
|
+
}
|
|
6685
|
+
|
|
6686
|
+
export function failedTestExternalDiagnosticReadPaths(
|
|
6687
|
+
config = {},
|
|
6688
|
+
state = {},
|
|
6689
|
+
testRun = null
|
|
6690
|
+
) {
|
|
6691
|
+
const failure = testRun || currentFailedProjectTest(state)?.test;
|
|
6692
|
+
const command = String(failure?.command || "").trim();
|
|
6693
|
+
if (!command) return [];
|
|
6694
|
+
const commandCwd = path.resolve(
|
|
6695
|
+
config.commandCwd || state.commandCwd || process.cwd()
|
|
6696
|
+
);
|
|
6697
|
+
const candidates = [];
|
|
6698
|
+
for (const token of tokenizeShellWords(command)) {
|
|
6699
|
+
const rawPath = String(token || "").replace(/[;,]+$/g, "").trim();
|
|
6700
|
+
if (!rawPath || !path.isAbsolute(rawPath)) continue;
|
|
6701
|
+
let realPath = "";
|
|
6702
|
+
try {
|
|
6703
|
+
realPath = fsSync.realpathSync(rawPath);
|
|
6704
|
+
const stat = fsSync.statSync(realPath);
|
|
6705
|
+
if (!stat.isFile() || stat.size > 1_000_000) continue;
|
|
6706
|
+
} catch {
|
|
6707
|
+
continue;
|
|
6708
|
+
}
|
|
6709
|
+
const relative = path.relative(commandCwd, realPath);
|
|
6710
|
+
if (!relative.startsWith("..") && !path.isAbsolute(relative)) continue;
|
|
6711
|
+
const normalized = realPath.replace(/\\/g, "/");
|
|
6712
|
+
if (
|
|
6713
|
+
!PLAIN_TEXT_FILE_EXTENSIONS.has(path.extname(normalized).toLowerCase()) ||
|
|
6714
|
+
/(?:secret|credential|password|private[-_]?key|access[-_]?token)/i.test(normalized) ||
|
|
6715
|
+
!(
|
|
6716
|
+
pathLooksLikeTestSource(normalized) ||
|
|
6717
|
+
/(?:^|\/)(?:acceptance|verification)(?:\/|$)|(?:contract|validator)/i.test(
|
|
6718
|
+
normalized
|
|
6719
|
+
)
|
|
6720
|
+
) ||
|
|
6721
|
+
candidates.includes(realPath)
|
|
6722
|
+
) {
|
|
6723
|
+
continue;
|
|
6724
|
+
}
|
|
6725
|
+
candidates.push(realPath);
|
|
6726
|
+
if (candidates.length >= 3) break;
|
|
6727
|
+
}
|
|
6728
|
+
return candidates;
|
|
6729
|
+
}
|
|
6730
|
+
|
|
6627
6731
|
function recoveryEvidenceDependencies(sourcePath = "", content = "") {
|
|
6628
6732
|
const dependencies = [];
|
|
6629
6733
|
const append = (candidate) => {
|
|
@@ -6984,8 +7088,17 @@ export async function buildFailedTestRecoveryPacket(config = {}, state = {}) {
|
|
|
6984
7088
|
]
|
|
6985
7089
|
.map(safeRecoveryEvidencePath)
|
|
6986
7090
|
.filter(Boolean);
|
|
7091
|
+
const mutationRepairPaths = failedTestMutationRepairPaths(
|
|
7092
|
+
config,
|
|
7093
|
+
state,
|
|
7094
|
+
testRun,
|
|
7095
|
+
taskContract.excludedOutputPaths || []
|
|
7096
|
+
);
|
|
6987
7097
|
const mutationEvidencePaths = new Set(
|
|
6988
|
-
|
|
7098
|
+
[
|
|
7099
|
+
...mutationRepairPaths,
|
|
7100
|
+
...(Array.isArray(verification.lastMutation?.paths) ? verification.lastMutation.paths : []),
|
|
7101
|
+
]
|
|
6989
7102
|
.map(safeRecoveryEvidencePath)
|
|
6990
7103
|
.filter(Boolean)
|
|
6991
7104
|
);
|
|
@@ -7476,8 +7589,33 @@ export async function buildFailedTestRecoveryPacket(config = {}, state = {}) {
|
|
|
7476
7589
|
at: new Date().toISOString(),
|
|
7477
7590
|
focuses: diagnosticFocuses,
|
|
7478
7591
|
};
|
|
7592
|
+
const evidencePaths = [...seen].filter((item) =>
|
|
7593
|
+
excerpts.some((excerpt) => excerpt.startsWith(`### ${item}\n`))
|
|
7594
|
+
);
|
|
7595
|
+
const diagnosticRepairPaths = diagnosticFocuses
|
|
7596
|
+
.map((focus) => safeRecoveryEvidencePath(focus?.path))
|
|
7597
|
+
.filter(Boolean);
|
|
7598
|
+
const preferredRepairPaths = [
|
|
7599
|
+
...diagnosticRepairPaths,
|
|
7600
|
+
...mutationRepairPaths,
|
|
7601
|
+
]
|
|
7602
|
+
.filter((item, index, items) => items.indexOf(item) === index)
|
|
7603
|
+
.filter((item) => evidencePaths.includes(item));
|
|
7604
|
+
const fallbackRepairPaths = evidencePaths
|
|
7605
|
+
.filter((item) => !pathLooksLikeTestSource(item))
|
|
7606
|
+
.filter(
|
|
7607
|
+
(item) =>
|
|
7608
|
+
filterExplicitlyExcludedOutputPaths(
|
|
7609
|
+
[item],
|
|
7610
|
+
taskContract.excludedOutputPaths || []
|
|
7611
|
+
).length > 0
|
|
7612
|
+
);
|
|
7479
7613
|
return {
|
|
7480
|
-
paths:
|
|
7614
|
+
paths: evidencePaths,
|
|
7615
|
+
repairPaths: (preferredRepairPaths.length
|
|
7616
|
+
? preferredRepairPaths
|
|
7617
|
+
: fallbackRepairPaths
|
|
7618
|
+
).slice(0, 6),
|
|
7481
7619
|
content: [
|
|
7482
7620
|
`Bounded failed-test evidence packet v${FAILED_TEST_RECOVERY_PACKET_VERSION}. These are exact current workspace excerpts selected from the discovered test and its local dependencies. Use them to calculate the producing transformation; do not restart broad discovery.`,
|
|
7483
7621
|
testRun.command ? `Verification command: ${testRun.command}` : "",
|
|
@@ -11359,6 +11497,39 @@ export function nextStepRuntimeConfig(config = {}, state = {}) {
|
|
|
11359
11497
|
.slice(0, 8);
|
|
11360
11498
|
const toolLoop = state.meta?.toolLoop || {};
|
|
11361
11499
|
const stagnationEpoch = Math.max(0, Number(toolLoop.stagnationEpoch || 0));
|
|
11500
|
+
const externalDiagnosticPaths = failedTestExternalDiagnosticReadPaths(
|
|
11501
|
+
runtimeConfig,
|
|
11502
|
+
state,
|
|
11503
|
+
retainedFailedTest
|
|
11504
|
+
);
|
|
11505
|
+
const consumedExternalDiagnosticPaths = new Set(
|
|
11506
|
+
(Array.isArray(toolLoop.recent) ? toolLoop.recent : [])
|
|
11507
|
+
.filter(
|
|
11508
|
+
(entry) =>
|
|
11509
|
+
entry?.ok === true &&
|
|
11510
|
+
entry?.blocked !== true &&
|
|
11511
|
+
String(entry?.toolName || "") === "read_file" &&
|
|
11512
|
+
Number(entry?.goalRevision || 0) === groundingGoalRevision
|
|
11513
|
+
)
|
|
11514
|
+
.map((entry) => {
|
|
11515
|
+
const rawPath = String(entry?.path || "").trim();
|
|
11516
|
+
return rawPath ? path.resolve(commandCwd, rawPath) : "";
|
|
11517
|
+
})
|
|
11518
|
+
.filter(Boolean)
|
|
11519
|
+
);
|
|
11520
|
+
runtimeConfig.testFailureDiagnosticReadPaths = externalDiagnosticPaths.filter(
|
|
11521
|
+
(candidate) => !consumedExternalDiagnosticPaths.has(candidate)
|
|
11522
|
+
);
|
|
11523
|
+
if (runtimeConfig.testFailureDiagnosticReadPaths.length) {
|
|
11524
|
+
runtimeConfig.readOnlyRoots = [
|
|
11525
|
+
...(Array.isArray(runtimeConfig.readOnlyRoots)
|
|
11526
|
+
? runtimeConfig.readOnlyRoots
|
|
11527
|
+
: []),
|
|
11528
|
+
...runtimeConfig.testFailureDiagnosticReadPaths.map((candidate) =>
|
|
11529
|
+
path.dirname(candidate)
|
|
11530
|
+
),
|
|
11531
|
+
].filter((item, index, items) => items.indexOf(item) === index);
|
|
11532
|
+
}
|
|
11362
11533
|
const currentRecoveryPacket = Boolean(
|
|
11363
11534
|
state.meta?.failedTestRecoveryPacket &&
|
|
11364
11535
|
Number(state.meta.failedTestRecoveryPacket.packetVersion || 0) ===
|
|
@@ -11676,9 +11847,7 @@ export function nextStepRuntimeConfig(config = {}, state = {}) {
|
|
|
11676
11847
|
);
|
|
11677
11848
|
});
|
|
11678
11849
|
const recoveryPacketPaths = currentRecoveryPacket
|
|
11679
|
-
? (
|
|
11680
|
-
? state.meta.failedTestRecoveryPacket.paths
|
|
11681
|
-
: [])
|
|
11850
|
+
? failedTestCanonicalRepairPaths(state)
|
|
11682
11851
|
.map(safeRecoveryEvidencePath)
|
|
11683
11852
|
.filter(Boolean)
|
|
11684
11853
|
.filter((item, index, items) => items.indexOf(item) === index)
|
|
@@ -13420,9 +13589,7 @@ function requiredDeclarationIdentitiesForPatch(state = {}, targetPath = "") {
|
|
|
13420
13589
|
}
|
|
13421
13590
|
|
|
13422
13591
|
function requiredSymbolRepairPath(state = {}, owner = "") {
|
|
13423
|
-
const sourcePaths = (state
|
|
13424
|
-
.map((item) => safeRecoveryEvidencePath(item))
|
|
13425
|
-
.filter(Boolean)
|
|
13592
|
+
const sourcePaths = failedTestCanonicalRepairPaths(state)
|
|
13426
13593
|
.filter((item) => !/(?:^|\/)tests?(?:\/|$)/i.test(item));
|
|
13427
13594
|
const ownerBasename = String(owner || "")
|
|
13428
13595
|
.split(".")
|
|
@@ -16542,7 +16709,7 @@ async function recordToolContractViolation({
|
|
|
16542
16709
|
const completedRequestedPaths = requestedCalls
|
|
16543
16710
|
.map((call) => call.path)
|
|
16544
16711
|
.filter((item) => item && completedArtifacts.has(item));
|
|
16545
|
-
const repairPaths = (state
|
|
16712
|
+
const repairPaths = failedTestCanonicalRepairPaths(state)
|
|
16546
16713
|
.map((item) => String(item || "").replace(/\\/g, "/"))
|
|
16547
16714
|
.filter((item) => item && !/(?:^|\/)tests?(?:\/|$)/i.test(item))
|
|
16548
16715
|
.slice(0, 6);
|
|
@@ -17423,9 +17590,7 @@ export function recoverUnavailableVerificationRerunAsCanonicalRead(
|
|
|
17423
17590
|
...(Array.isArray(config.testFailureRepairPatchTargets)
|
|
17424
17591
|
? config.testFailureRepairPatchTargets.map((target) => target?.path)
|
|
17425
17592
|
: []),
|
|
17426
|
-
...(
|
|
17427
|
-
? state.meta.failedTestRecoveryPacket.paths
|
|
17428
|
-
: []),
|
|
17593
|
+
...failedTestCanonicalRepairPaths(state),
|
|
17429
17594
|
]
|
|
17430
17595
|
.map(safeRecoveryEvidencePath)
|
|
17431
17596
|
.filter(Boolean)
|
|
@@ -19210,6 +19375,7 @@ async function runAgentOnceUnlocked(config) {
|
|
|
19210
19375
|
packetVersion: FAILED_TEST_RECOVERY_PACKET_VERSION,
|
|
19211
19376
|
content: recoveryEvidence.content,
|
|
19212
19377
|
paths: recoveryEvidence.paths,
|
|
19378
|
+
repairPaths: recoveryEvidence.repairPaths,
|
|
19213
19379
|
mutationRevision: Number(currentFailure.mutationRevision || 0),
|
|
19214
19380
|
failureSignature: String(currentFailure.failureSignature || ""),
|
|
19215
19381
|
command: String(currentFailure.command || ""),
|
|
@@ -20488,6 +20654,7 @@ async function runAgentOnceUnlocked(config) {
|
|
|
20488
20654
|
packetVersion: FAILED_TEST_RECOVERY_PACKET_VERSION,
|
|
20489
20655
|
content: recoveryEvidence.content,
|
|
20490
20656
|
paths: recoveryEvidence.paths,
|
|
20657
|
+
repairPaths: recoveryEvidence.repairPaths,
|
|
20491
20658
|
mutationRevision: Number(currentFailure.mutationRevision || 0),
|
|
20492
20659
|
failureSignature: String(currentFailure.failureSignature || ""),
|
|
20493
20660
|
command: String(currentFailure.command || ""),
|
|
@@ -733,6 +733,8 @@ function constrainReadFilePaths(tool, paths, phase) {
|
|
|
733
733
|
? "Exact canonical project file selected from current task evidence for the required fresh correction."
|
|
734
734
|
: phase === "failed-test-evidence-refresh"
|
|
735
735
|
? "Exact unread workspace-relative path retained by the current failed-test evidence packet."
|
|
736
|
+
: phase === "failed-test-diagnostic-read"
|
|
737
|
+
? "Exact read-only acceptance or validator source named by the retained failed verification command."
|
|
736
738
|
: "Exact workspace-relative path discovered by inspect_project.",
|
|
737
739
|
};
|
|
738
740
|
return {
|
|
@@ -746,6 +748,8 @@ function constrainReadFilePaths(tool, paths, phase) {
|
|
|
746
748
|
? "Read one exact canonical project file before the required fresh source correction. Tests, Git actions, and finish remain unavailable until a material patch advances the project mutation revision."
|
|
747
749
|
: phase === "failed-test-evidence-refresh"
|
|
748
750
|
? "Read one exact unread source or acceptance-test file from the current failed-test evidence packet. Each packet path is exposed at most once before mutation-only recovery resumes."
|
|
751
|
+
: phase === "failed-test-diagnostic-read"
|
|
752
|
+
? "Read one exact existing external acceptance or validator file from the retained failed command. This path is read-only and no neighboring external files are exposed."
|
|
749
753
|
: phase === "read-instructions"
|
|
750
754
|
? "Read one exact project instruction file discovered by inspect_project before repository mutation or validation commands are enabled."
|
|
751
755
|
: phase === "read-tests"
|
|
@@ -2017,24 +2021,36 @@ export function selectProgressiveTools(
|
|
|
2017
2021
|
.filter((item, index, items) => items.indexOf(item) === index)
|
|
2018
2022
|
.slice(0, 1)
|
|
2019
2023
|
: [];
|
|
2020
|
-
const
|
|
2021
|
-
?
|
|
2022
|
-
|
|
2024
|
+
const diagnosticReadPaths = Array.isArray(config.testFailureDiagnosticReadPaths)
|
|
2025
|
+
? config.testFailureDiagnosticReadPaths
|
|
2026
|
+
.map((item) => String(item || "").replace(/\\/g, "/").trim())
|
|
2027
|
+
.filter(Boolean)
|
|
2028
|
+
.filter((item, index, items) => items.indexOf(item) === index)
|
|
2029
|
+
.slice(0, 3)
|
|
2030
|
+
: [];
|
|
2031
|
+
const boundedRepairReadPaths = [
|
|
2032
|
+
...diagnosticReadPaths,
|
|
2033
|
+
...(repairContextPaths.length ? repairContextPaths : optionalRepairRereadPaths),
|
|
2034
|
+
]
|
|
2035
|
+
.filter((item, index, items) => items.indexOf(item) === index)
|
|
2036
|
+
.slice(0, 8);
|
|
2023
2037
|
const constrainedRepairRead = boundedRepairReadPaths.length
|
|
2024
2038
|
? constrainReadFilePaths(
|
|
2025
2039
|
available.get("read_file"),
|
|
2026
2040
|
boundedRepairReadPaths,
|
|
2027
|
-
|
|
2028
|
-
? "failed-test-
|
|
2029
|
-
:
|
|
2041
|
+
diagnosticReadPaths.length
|
|
2042
|
+
? "failed-test-diagnostic-read"
|
|
2043
|
+
: repairContextPaths.length
|
|
2044
|
+
? "failed-test-evidence-refresh"
|
|
2045
|
+
: "deepseek-failed-test-source-reread"
|
|
2030
2046
|
)
|
|
2031
2047
|
: available.get("read_file");
|
|
2032
2048
|
const toolNames = config.testFailureRepairMutationRequired === true
|
|
2033
2049
|
? [
|
|
2034
|
-
...(
|
|
2035
|
-
? ["read_file"
|
|
2036
|
-
:
|
|
2037
|
-
? ["read_file"]
|
|
2050
|
+
...(boundedRepairReadPaths.length
|
|
2051
|
+
? ["read_file"]
|
|
2052
|
+
: config.testFailureRepairNeedsPatchContext === true
|
|
2053
|
+
? ["read_file", "search_files"]
|
|
2038
2054
|
: []),
|
|
2039
2055
|
"apply_patch",
|
|
2040
2056
|
...(constrainedInstructionCreate ? ["write_file"] : []),
|
package/src/scs-evidence.js
CHANGED
|
@@ -542,12 +542,26 @@ export function filterExplicitlyExcludedOutputPaths(paths = [], exclusions = [])
|
|
|
542
542
|
}
|
|
543
543
|
|
|
544
544
|
export function inferExplicitlyExcludedOutputPaths(goal = "") {
|
|
545
|
+
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";
|
|
545
546
|
// Preserve coordinated path lists that wrap after a comma. Prompt and task
|
|
546
547
|
// files commonly format "do not modify a, b,\nc, or d" across lines; splitting
|
|
547
548
|
// that text first drops the governing negative action from the continuation.
|
|
548
|
-
const
|
|
549
|
+
const negativePrefix = "(?:do\\s+not|don't|dont|must\\s+not|should\\s+not|never)";
|
|
550
|
+
const negativeAction = "(?:run|rerun|re-run|execut(?:e|ed|ing)|creat(?:e|ed|ing)|recreat(?:e|ed|ing)|writ(?:e|ten|ing)|generat(?:e|ed|ing)|sav(?:e|ed|ing)|output|touch|modif(?:y|ied|ying)|edit(?:ed|ing)?|stage|commit)";
|
|
551
|
+
const wrappedNegativeAction = new RegExp(
|
|
552
|
+
`(\\b${negativePrefix}\\b)\\s*\\r?\\n\\s*(?=${negativeAction}\\b)`,
|
|
553
|
+
"giu"
|
|
554
|
+
);
|
|
555
|
+
const wrappedNegativePath = new RegExp(
|
|
556
|
+
`(\\b${negativePrefix}\\b[^.!?。!?;;\\n]{0,180}\\b${negativeAction}\\b)\\s*\\r?\\n\\s*` +
|
|
557
|
+
`(?=\\S{1,260}\\.(?:${extensionPattern})\\b)`,
|
|
558
|
+
"giu"
|
|
559
|
+
);
|
|
560
|
+
const source = String(goal || "")
|
|
561
|
+
.replace(/([,,、])\s*\r?\n\s*/gu, "$1 ")
|
|
562
|
+
.replace(wrappedNegativeAction, "$1 ")
|
|
563
|
+
.replace(wrappedNegativePath, "$1 ");
|
|
549
564
|
if (!source.trim()) return [];
|
|
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";
|
|
551
565
|
const pathPattern = new RegExp(
|
|
552
566
|
'((?:~|\\.{1,2}|/|[A-Za-z0-9_\\-\\u4e00-\\u9fff])[\\w./~\\-\\u4e00-\\u9fff]{0,260}\\.(?:' +
|
|
553
567
|
extensionPattern +
|