@lazyingart/agintiflow 0.20.337-integration.0 → 0.20.339-integration.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.
@@ -66,6 +66,15 @@ wall time. No external Codex/Claude/Gemini agent wrapper was called. The existin
66
66
  Docker image was reused; no GPU model, GUI desktop, or dependency rebuild was
67
67
  needed. The test-created containers exited after each command.
68
68
 
69
+ The packaged CLI was then installed globally and tested again in a separate fresh
70
+ workspace, using the installed entry point rather than the source checkout. All
71
+ three cases passed again: summary in 6.8 seconds / 4 turns, code repair in 37.1
72
+ seconds / 5 turns, and Chinese follow-up in 16.7 seconds / 4 additional turns.
73
+ The same independent checks passed, including all 22 oracle assertions and
74
+ unchanged input/code/test bytes where required. The installed package also passed
75
+ the 13 focused lifecycle and CLI-policy regressions. These timings describe that
76
+ individual run and are not a throughput guarantee.
77
+
69
78
  ## Usage
70
79
 
71
80
  See [DeepSeek CLI fallback](../docs/deepseek-cli-fallback.md) for start/resume,
@@ -0,0 +1,62 @@
1
+ # DeepSeek Artifact Completion and Host Integration
2
+
3
+ Machine hosts should invoke both new and resumed AgInTi turns with
4
+ `--no-wrappers` when AgInTi is the fallback for an unavailable external agent.
5
+ Keep the provider explicit; credentials do not authorize a provider switch.
6
+ Use the host's existing routines rather than rewriting them in the agent loop.
7
+
8
+ ## Source Changes Are Not Artifact Changes
9
+
10
+ A task that reads inputs and writes a separate summary must not be pushed into
11
+ editing those inputs. A task that creates or updates artifacts inside an exact
12
+ host-provided root must not be pushed into changing the generator's source.
13
+ Private task files deliberately do not increment the project-source revision.
14
+
15
+ Execution and completion now share bounded artifact-root resolution. A real
16
+ current-turn scoped write can satisfy artifact freshness without an unrelated
17
+ project edit. Its saved timestamp must follow the current execution contract;
18
+ old mutations, no-op patches, and workspace-wide roots do not qualify for this
19
+ exemption. Explicit input repairs still require their requested changes.
20
+ After a verified scoped write satisfies a prior missing-file/freshness repair,
21
+ the runtime also stops enforcing that retained repair's obsolete source-edit
22
+ phase. Actual source or artifact quality defects remain blocking. Keeping the
23
+ current contract correct without retiring the obsolete phase can still trap a
24
+ valid routine in repeated no-op patches.
25
+ File, command, requested-format, source-grounding, and quality evidence gates
26
+ remain active. In particular, a pre-existing PDF cannot satisfy a request to
27
+ materially revise and rebuild it.
28
+
29
+ Postfix input declarations such as `requirements.txt is a read-only input`
30
+ are recognized without accidentally excluding a neighboring output path.
31
+ Coordinated preservation instructions such as `leave a.txt and b.txt untouched`
32
+ exclude both inputs from deliverables, not just paths adjacent to the verb.
33
+ An output requested after that preservation clause remains required.
34
+
35
+ ## Source-Free Answers
36
+
37
+ Refusing to invent a forecast is not a forecast. Chinese and English negated
38
+ forecast clauses are stripped before assessing whether an answer needs source
39
+ evidence. A real prediction later in the same sentence remains evidence-gated.
40
+ Likewise, saying an item is unverified, pending confirmation, or needs no repeat
41
+ confirmation is not a claim that it has been independently validated. Only the
42
+ negated phrase is removed; real validation claims in the remaining text still
43
+ require evidence.
44
+
45
+ ## Validation
46
+
47
+ Run the evidence-visibility, truthful-completion, and scoped-artifact-research
48
+ smokes, then the full `npm test`. The LabCanvas host adds separate mocked
49
+ timeout/session/concurrency tests and opt-in live DeepSeek acceptance:
50
+
51
+ ```bash
52
+ python scripts/evaluate_aginti_fallback.py --live --command /path/to/bin/aginti-cli.js
53
+ ```
54
+
55
+ The host test uses synthetic inputs, isolated session registries, actual routine
56
+ commands, a compiled Chinese memo PDF, and resumed turns. It prohibits external
57
+ chat sends, public publication, and external agent wrappers. Saved inputs and
58
+ attempted tool writes are checked independently of the model's final answer.
59
+
60
+ This is acceptance for simple host tasks, not a claim that DeepSeek matches
61
+ Codex across all tasks. Keep model/provider limitations separate from agent-loop
62
+ or host-integration failures.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lazyingart/agintiflow",
3
- "version": "0.20.337-integration.0",
3
+ "version": "0.20.339-integration.0",
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",
@@ -98,6 +98,21 @@ assert.deepEqual(immutableInputsContract.exactInputPaths, ["notes.txt", "risks.t
98
98
  assert.deepEqual(immutableInputsContract.exactOutputPaths, ["summary.md"]);
99
99
  assert.deepEqual(immutableInputsContract.excludedOutputPaths, ["notes.txt", "risks.txt"]);
100
100
  assert.equal(immutableInputsContract.requiresSourceGrounding, true);
101
+ const coordinatedUntouchedInputsContract = deriveScsTaskContract({
102
+ goal: "Read notes.txt and risks.txt. Create artifacts/summary.md. Leave notes.txt and risks.txt untouched, then write artifacts/result.json.",
103
+ });
104
+ assert.deepEqual(coordinatedUntouchedInputsContract.excludedOutputPaths, ["notes.txt", "risks.txt"]);
105
+ assert.deepEqual(coordinatedUntouchedInputsContract.exactOutputPaths, ["artifacts/summary.md", "artifacts/result.json"]);
106
+ assert.deepEqual(coordinatedUntouchedInputsContract.exactInputPaths, ["notes.txt", "risks.txt"]);
107
+ const postfixReadonlyInputContract = deriveScsTaskContract({
108
+ goal: "Create a scene in bench.scene.json. requirements.txt is a read-only input.",
109
+ });
110
+ assert.deepEqual(postfixReadonlyInputContract.exactOutputPaths, ["bench.scene.json"]);
111
+ assert.deepEqual(postfixReadonlyInputContract.exactInputPaths, ["requirements.txt"]);
112
+ assert.deepEqual(postfixReadonlyInputContract.excludedOutputPaths, ["requirements.txt"]);
113
+ assert.deepEqual(deriveScsTaskContract({
114
+ goal: "Create summary.md. `source.json` must remain immutable. Then update output.json.",
115
+ }).excludedOutputPaths, ["source.json"], "postfix write protection leaked onto a later output");
101
116
  assert.deepEqual(evaluateScsSemanticContract(immutableInputsContract, {
102
117
  commandCwd: scopedReadThenWriteRoot,
103
118
  events: [{ type: "tool.completed", data: { ok: true, toolName: "read_file", path: "notes.txt", content: "first input" } }],
@@ -9,6 +9,7 @@ import {
9
9
  assessResponseOnlyEmptyEnvelope,
10
10
  assessResponseOnlyPerfectAudit,
11
11
  completionRequirementCoverageInstruction,
12
+ completionTaskContract,
12
13
  continuationExecutionContractDirective,
13
14
  evaluateAuthoritativeStructuredCompletionCoverage,
14
15
  nextStepRuntimeConfig,
@@ -1214,6 +1215,16 @@ for (const candidateResult of [
1214
1215
  "No forecast is requested; please clarify what this number means.",
1215
1216
  "这不是预测;这串数字缺少上下文,无法判断它的含义。",
1216
1217
  "これは予測ではありません。この数字だけでは文脈が不足しており、意味を判断できません。",
1218
+ "对两类客户群做事实性对比,只呈现现有资料中的差异,不编造营收预测。",
1219
+ "对两个客户群做事实对比,不编造收入预测。",
1220
+ "任务是对两个客户群体做事实性对比,不做虚构营收预测。",
1221
+ "只做两个客户群的事实对比,不做收入预测。",
1222
+ "对两个客户细分做事实对比,不做臆测性营收预测。",
1223
+ "对两类客户客群做事实性对比,不使用收入预测。",
1224
+ "结论以现有可得资料为限,未证实部分明确标注为待确认。",
1225
+ "已确定事项不再重复确认。",
1226
+ "Compare the customer groups; do not invent revenue forecasts.",
1227
+ "Never fabricate market predictions.",
1217
1228
  ]) {
1218
1229
  const negatedForecastClarification = evaluateSourceFreeResponseClaims({
1219
1230
  goal: sourceFreeResearchGoal,
@@ -1231,6 +1242,10 @@ for (const candidateResult of [
1231
1242
  "No forecast was requested, but demand will grow next year.",
1232
1243
  "这串数字缺少上下文,但报告预测市场需求明年会增长。",
1233
1244
  "予測ではありませんが、市場需要は来年増加する見込みです。",
1245
+ "不编造营收预测,但报告预测市场需求明年会增长。",
1246
+ "Do not invent revenue forecasts, but demand will grow next year.",
1247
+ "不做臆测性营收预测,但报告预测市场需求明年会增长。",
1248
+ "资料未证实部分待确认,但实验已经验证成功。",
1234
1249
  ]) {
1235
1250
  const disguisedForecast = evaluateSourceFreeResponseClaims({
1236
1251
  goal: sourceFreeResearchGoal,
@@ -2488,6 +2503,17 @@ try {
2488
2503
  assert.equal(editRuntime.completionFreshMutationRequired, true, `${verb}: actual input correction was exempted`);
2489
2504
  assert(editRuntime.completionFreshMutationPaths.includes("notes.txt"));
2490
2505
  }
2506
+ const artifactRuntime = nextStepRuntimeConfig({ goal, commandCwd: summaryWorkspace }, {
2507
+ goal,
2508
+ commandCwd: summaryWorkspace,
2509
+ meta: {
2510
+ goalContract: { revision: 1, currentRequest: goal, activeGoal: goal },
2511
+ activeExecutionContract: { revision: 1, requiresFileMutation: true, requiresSourceGrounding: true, startedMutationRevision: 0 },
2512
+ projectVerification: { mutationRevision: 0, mutationHistory: [] },
2513
+ },
2514
+ });
2515
+ assert.notEqual(artifactRuntime.completionFreshMutationRequired, true,
2516
+ `${id}: separate deliverable forced a correction of its input or an unrelated source`);
2491
2517
  }
2492
2518
 
2493
2519
  const summaryFollowup = await runCase({
@@ -2511,6 +2537,51 @@ try {
2511
2537
  assert.equal(await fs.readFile(path.join(followupWorkspace, "checklist.md"), "utf8"), "- Assign an archive owner.\n- Test the backup.\n");
2512
2538
 
2513
2539
  const crossTaskIsolationId = "scoped-artifact-cross-task-completion";
2540
+ for (const nestedRoot of [true, false]) {
2541
+ const workspace = path.join(tempRoot, "workspaces", "scoped-json-freshness");
2542
+ await fs.mkdir(path.join(workspace, "artifacts"), { recursive: true });
2543
+ await fs.writeFile(path.join(workspace, "requirements.txt"), "Keep the tool source read-only.\n");
2544
+ await fs.writeFile(path.join(workspace, "artifacts", "bench.scene.json"), "{}\n");
2545
+ const artifactRoot = nestedRoot ? path.join(workspace, "artifacts") : workspace;
2546
+ const goal = scopedTaskGoal(
2547
+ "Use the existing routine to create artifacts/bench.scene.json and validate it. requirements.txt is a read-only input.",
2548
+ artifactRoot
2549
+ );
2550
+ const state = {
2551
+ goal, commandCwd: workspace,
2552
+ meta: {
2553
+ goalContract: { revision: 1, currentRequest: goal, activeGoal: goal },
2554
+ activeExecutionContract: {
2555
+ revision: 1, requiresFileMutation: true, requiresSourceGrounding: true, startedMutationRevision: 0,
2556
+ refreshedAt: "2026-10-01T05:00:00Z",
2557
+ scopedArtifactMutationAt: "2026-10-01T05:00:01Z",
2558
+ },
2559
+ projectVerification: { mutationRevision: 0, mutationHistory: [] },
2560
+ },
2561
+ };
2562
+ const contract = completionTaskContract({ goal, commandCwd: workspace }, state);
2563
+ assert.equal(contract.requiredFreshMutationRevision, nestedRoot ? 0 : 1,
2564
+ "task artifact writes were confused with project source corrections, or a workspace-wide root bypassed freshness");
2565
+ assert(contract.requiredEvidence.some((item) => item.category === "file"),
2566
+ "artifact creation must still require real file evidence");
2567
+ assert(contract.requiredEvidence.every((item) => !nestedRoot || !item.minimumMutationRevision));
2568
+ state.meta.completionEvidenceRepair = {
2569
+ key: "previous-file-evidence-rejection", at: "2026-10-01T05:00:00.500Z",
2570
+ requiresFreshFileMutation: true, requiredFreshMutationRevision: 1,
2571
+ };
2572
+ const runtime = nextStepRuntimeConfig({ goal, commandCwd: workspace }, state);
2573
+ assert.equal(runtime.completionFreshMutationRequired === true, !nestedRoot,
2574
+ "a satisfied artifact mutation remained trapped in the retained fresh-source repair phase");
2575
+ if (nestedRoot) {
2576
+ state.meta.completionEvidenceRepair.artifactQualityRepairRequired = true;
2577
+ assert.equal(nextStepRuntimeConfig({ goal, commandCwd: workspace }, state).completionFreshMutationRequired, true,
2578
+ "a fresh artifact write cannot waive an outstanding quality defect");
2579
+ state.meta.completionEvidenceRepair.artifactQualityRepairRequired = false;
2580
+ }
2581
+ state.meta.activeExecutionContract.scopedArtifactMutationAt = "2026-10-01T04:59:00Z";
2582
+ assert.equal(completionTaskContract({ goal, commandCwd: workspace }, state).requiredFreshMutationRevision, 1,
2583
+ "a prior artifact mutation cannot satisfy the current revision");
2584
+ }
2514
2585
  const crossTaskWorkspace = path.join(tempRoot, "workspaces", crossTaskIsolationId);
2515
2586
  const currentTaskRoot = path.join(crossTaskWorkspace, "output", "tasks", "current-task");
2516
2587
  const siblingTaskRoot = path.join(crossTaskWorkspace, "output", "tasks", "sibling-task");
@@ -18940,6 +18940,23 @@ function groundedProjectTaskInstructionText(state = {}, config = {}, directContr
18940
18940
  }
18941
18941
  }
18942
18942
 
18943
+ function scopedArtifactTaskRoot(contract = {}, goal = "", commandCwd = process.cwd()) {
18944
+ const root = scopedArtifactRoot(goal);
18945
+ if (!root) return "";
18946
+ const cwd = path.resolve(commandCwd);
18947
+ const resolvedRoot = path.resolve(root);
18948
+ const relativeRoot = path.relative(cwd, resolvedRoot);
18949
+ if (!relativeRoot || relativeRoot.startsWith("..") || path.isAbsolute(relativeRoot)) return "";
18950
+ const outputs = Array.isArray(contract.exactOutputPaths) ? contract.exactOutputPaths : [];
18951
+ const scopedOutputs = outputs.length > 0 && outputs.every((item) => {
18952
+ const relative = path.relative(resolvedRoot, path.resolve(cwd, item));
18953
+ return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative));
18954
+ });
18955
+ return contract.scopedArtifactDeliverable || contract.scopedArtifactOperation || scopedOutputs
18956
+ ? relativeRoot.replace(/\\/g, "/")
18957
+ : "";
18958
+ }
18959
+
18943
18960
  export function completionTaskContract(config = {}, state = {}) {
18944
18961
  const taskProfile = config.taskProfile || state.meta?.taskProfile || "auto";
18945
18962
  const contractGoal = completionContractGoal(config, state);
@@ -19021,9 +19038,22 @@ export function completionTaskContract(config = {}, state = {}) {
19021
19038
  const scopedArtifactDeliverable = currentContract
19022
19039
  ? currentContract.scopedArtifactDeliverable === true
19023
19040
  : activeExecutionContract.scopedArtifactDeliverable === true;
19041
+ const scopedMutationAt = Date.parse(String(activeExecutionContract.scopedArtifactMutationAt || ""));
19042
+ const refreshedAt = Date.parse(String(activeExecutionContract.refreshedAt || ""));
19043
+ const freshScopedMutation = Boolean(
19044
+ scopedArtifactTaskRoot(
19045
+ currentContract || contract, currentRequest || contractGoal,
19046
+ config.commandCwd || state.commandCwd || process.cwd()
19047
+ ) &&
19048
+ Number.isFinite(scopedMutationAt) && Number.isFinite(refreshedAt) &&
19049
+ scopedMutationAt >= refreshedAt &&
19050
+ (currentContract?.exactInputPaths || []).every(
19051
+ (input) => !documentSourceMutationExplicitlyRequested(state, config, input)
19052
+ )
19053
+ );
19024
19054
  const requiresFreshMutation = Boolean(
19025
19055
  (currentContract?.requiresFileMutation || activeExecutionContract.requiresFileMutation) &&
19026
- !scopedArtifactDeliverable
19056
+ !scopedArtifactDeliverable && !freshScopedMutation
19027
19057
  );
19028
19058
  const minimumMutationRevision = requiresFreshMutation
19029
19059
  ? startedMutationRevision + 1
@@ -19386,42 +19416,13 @@ export function nextStepRuntimeConfig(config = {}, state = {}) {
19386
19416
  const currentGroundingGoal = String(
19387
19417
  state.meta?.goalContract?.currentRequest || config.goal || state.goal || ""
19388
19418
  );
19389
- const scopedRoot = scopedArtifactRoot(completionContractGoal(config, state));
19390
19419
  const commandCwd = path.resolve(
19391
19420
  config.commandCwd || state.commandCwd || process.cwd()
19392
19421
  );
19393
- const resolvedScopedRoot = scopedRoot ? path.resolve(scopedRoot) : "";
19394
- const scopedRootRelative = resolvedScopedRoot
19395
- ? path.relative(commandCwd, resolvedScopedRoot)
19396
- : "";
19397
- const exactScopedOutputs = Array.isArray(groundingTaskContract.exactOutputPaths)
19398
- ? groundingTaskContract.exactOutputPaths
19399
- .map((item) => String(item || "").trim())
19400
- .filter(Boolean)
19401
- : [];
19402
- const exactOutputsStayInsideScopedRoot = Boolean(
19403
- resolvedScopedRoot &&
19404
- exactScopedOutputs.length > 0 &&
19405
- exactScopedOutputs.every((item) => {
19406
- const absoluteOutput = path.resolve(commandCwd, item);
19407
- const relativeOutput = path.relative(resolvedScopedRoot, absoluteOutput);
19408
- return (
19409
- relativeOutput === "" ||
19410
- (!relativeOutput.startsWith("..") && !path.isAbsolute(relativeOutput))
19411
- );
19412
- })
19413
- );
19414
- const scopedArtifactTask = Boolean(
19415
- (
19416
- groundingTaskContract.scopedArtifactDeliverable === true ||
19417
- groundingTaskContract.scopedArtifactOperation === true ||
19418
- exactOutputsStayInsideScopedRoot
19419
- ) &&
19420
- resolvedScopedRoot &&
19421
- scopedRootRelative &&
19422
- !scopedRootRelative.startsWith("..") &&
19423
- !path.isAbsolute(scopedRootRelative)
19422
+ const scopedRootRelative = scopedArtifactTaskRoot(
19423
+ groundingTaskContract, completionContractGoal(config, state), commandCwd
19424
19424
  );
19425
+ const scopedArtifactTask = Boolean(scopedRootRelative);
19425
19426
  if (scopedArtifactTask) {
19426
19427
  runtimeConfig.scopedArtifactTask = true;
19427
19428
  runtimeConfig.scopedArtifactRoot = scopedRootRelative.replace(/\\/g, "/");
@@ -19544,20 +19545,32 @@ export function nextStepRuntimeConfig(config = {}, state = {}) {
19544
19545
  ),
19545
19546
  retainedSourceQualityRepairRequired ? mutationRevision + 1 : 0
19546
19547
  );
19548
+ const artifactRepairBoundaryAt = Date.parse(String(completionRepair.at || ""));
19549
+ const scopedArtifactSatisfiedRepair = Boolean(
19550
+ groundingScopedArtifactMutationSatisfied &&
19551
+ Number.isFinite(artifactRepairBoundaryAt) && scopedArtifactMutationAt > artifactRepairBoundaryAt &&
19552
+ Number(groundingTaskContract.requiredFreshMutationRevision || 0) === 0 &&
19553
+ !retainedSourceQualityRepairRequired &&
19554
+ completionRepair.sourceQualityRepairRequired !== true &&
19555
+ completionRepair.artifactQualityRepairRequired !== true
19556
+ );
19547
19557
  const completionRepairRequiresFreshMutation = Boolean(
19548
- retainedSourceQualityRepairRequired ||
19549
- completionRepair.requiresFreshFileMutation === true ||
19558
+ !scopedArtifactSatisfiedRepair && (
19559
+ retainedSourceQualityRepairRequired ||
19560
+ completionRepair.requiresFreshFileMutation === true ||
19550
19561
  (
19551
19562
  completionRepair.key &&
19552
19563
  groundingTaskContract.requiresFileMutation === true &&
19553
19564
  completionFreshMutationRevision > mutationRevision
19554
19565
  )
19566
+ )
19555
19567
  );
19556
19568
  const currentTurnRequiresFreshMutation = Boolean(
19557
19569
  groundingExecutionContract.requiresFileMutation === true &&
19558
19570
  groundingExecutionContract.requiresSourceGrounding === true &&
19559
19571
  !groundingFreshMutationSatisfied &&
19560
- !groundingScopedArtifactMutationSatisfied
19572
+ !groundingScopedArtifactMutationSatisfied &&
19573
+ !separateSourceDeliverable
19561
19574
  );
19562
19575
  const explicitHeadRestore = currentTurnRequiresFreshMutation
19563
19576
  ? explicitlyRequestedDirtyHeadRestore(state, config)
@@ -891,8 +891,10 @@ export function inferExplicitlyExcludedOutputPaths(goal = "") {
891
891
  // later exclusion backwards across coordinated clauses.
892
892
  const negativeActionAfter =
893
893
  /^\s*(?:(?:does\s+not|doesn't|is\s+not|isn't)\s+exist\b\s*(?:and\s+)?)?(?:must\s+not|should\s+not|never)\s+(?:be\s+)?(?:run|rerun|re-run|execut(?:e|ed)|creat(?:e|ed)|recreat(?:e|ed)|writ(?:e|ten)|generat(?:e|ed)|sav(?:e|ed)|output|touch(?:ed)?|modif(?:y|ied)|edit(?:ed)?|stag(?:e|ed)|commit(?:ted)?)(?:\b|\s)/i;
894
+ const immutablePathAfter =
895
+ /^[`"'\s]*(?:is|remains?|must\s+remain|should\s+remain)\s+(?:(?:an?|the)\s+)?(?:read[ -]?only|immutable)\b/i;
894
896
  const keepAbsent =
895
- /\b(?:keep|leave)\b[^.!?。!?;;\n]{0,80}\b(?:absent|missing|nonexistent|uncreated|untouched)\b/i;
897
+ /\b(?:keep|leave)\b[^!?。!?;;\n]{0,300}?\b(?:absent|missing|nonexistent|uncreated|untouched)\b/gi;
896
898
  const cjkNegativeActionBefore =
897
899
  /(?:不要|不得|禁止|无需|不需要)[^。!?;\n]{0,140}(?:运行|执行|重跑|创建|建立|写入|生成|保存|输出|修改|编辑|提交|暂存)/u;
898
900
  const cjkNegativeActionAfter =
@@ -905,6 +907,7 @@ export function inferExplicitlyExcludedOutputPaths(goal = "") {
905
907
  for (const clause of source.split(/[;;\n]|(?<=[.!?。!?])\s+/u)) {
906
908
  pathPattern.lastIndex = 0;
907
909
  const matches = [...clause.matchAll(pathPattern)];
910
+ const preservedPathSpans = [...clause.matchAll(keepAbsent)];
908
911
  const immutablePathClause = Boolean(
909
912
  /\b(?:treat|consider|regard)\b[^!?。!?;;\n]{0,260}\b(?:as\s+)?(?:immutable|read[ -]?only)\b/i.test(
910
913
  clause
@@ -935,7 +938,10 @@ export function inferExplicitlyExcludedOutputPaths(goal = "") {
935
938
  immutablePathClause ||
936
939
  negativeActionBefore.test(before) ||
937
940
  negativeActionAfter.test(after) ||
938
- keepAbsent.test(`${before}${after}`) ||
941
+ immutablePathAfter.test(after) ||
942
+ preservedPathSpans.some((span) =>
943
+ index >= span.index && index + rawPath.length <= span.index + span[0].length
944
+ ) ||
939
945
  cjkNegativeActionBefore.test(before) ||
940
946
  cjkNegativeActionAfter.test(after) ||
941
947
  directRemovalBefore.test(before) ||
@@ -2203,7 +2209,15 @@ function sourceFreeClaimSegmentOnlyNegatesForecast(text = "") {
2203
2209
  " "
2204
2210
  )
2205
2211
  .replace(
2206
- /(?:不是|並非|并非|没有|沒有|无|無|不作|不做|无需|無需|不需要)(?:任何)?(?:预测|預測|预计|預計|推测|推測|预言|預言)/gu,
2212
+ /(?:不是|並非|并非|没有|沒有|无|無|不作|不做|不使用|无需|無需|不需要)[^\s,,。!?;;但而]{0,12}?(?:预测|預測|预计|預計|推测|推測|预言|預言)/gu,
2213
+ " "
2214
+ )
2215
+ .replace(
2216
+ /\b(?:do\s+not|don't|must\s+not|never)\s+(?:invent|fabricate|make\s+up)\s+(?:any\s+)?(?:(?:revenue|income|market|demand)\s+)?(?:forecasts?|predictions?|projections?)\b/giu,
2217
+ " "
2218
+ )
2219
+ .replace(
2220
+ /(?:不|不要|不得|禁止)(?:编造|編造|虚构|虛構|捏造|杜撰)(?:任何)?(?:营收|營收|收入|市场|市場|需求)?(?:预测|預測|预计|預計|推测|推測)/gu,
2207
2221
  " "
2208
2222
  )
2209
2223
  .replace(
@@ -2237,7 +2251,11 @@ function sourceFreeExternalClaimCategoriesForSegment(
2237
2251
  text = "",
2238
2252
  { requireNamedEvidenceGrounding = false } = {}
2239
2253
  ) {
2240
- const value = String(text || "");
2254
+ // Remove only negated verification phrases; reassess the remaining clause
2255
+ // so a real evidence claim beside a disclaimer still requires a source.
2256
+ const value = String(text || "")
2257
+ .replace(/(?:尚未|未经|未經|未|待)(?:被|得到|经过|經過)?(?:验证|驗證|核实|核實|证实|證實|确认|確認|证明|證明)/gu, " ")
2258
+ .replace(/(?:不再|不必|无需|無需|无须|無須)[^\s,,。!?;;但而]{0,12}?(?:验证|驗證|核实|核實|证实|證實|确认|確認|证明|證明)/gu, " ");
2241
2259
  if (!value.trim()) return [];
2242
2260
  const categories = [];
2243
2261
  const add = (category, pattern) => {