@lazyingart/agintiflow 0.20.264 → 0.20.266

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.264",
3
+ "version": "0.20.266",
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",
@@ -159,6 +159,12 @@ try {
159
159
  assert(defaultMaxStepsForProfile("pipeline") >= 44, "pipeline profile step budget is too low for repair/verify/resume loops");
160
160
  assert(!/misleading failing test/i.test(qaProfile.prompt), "QA profile still encourages misleading test fixtures");
161
161
  assert(/do not stage fake bugs/i.test(qaProfile.prompt), "QA profile does not discourage fake staged failures");
162
+ const slidesProfile = listTaskProfiles().find((profile) => profile.id === "slides");
163
+ assert(slidesProfile, "slides profile is missing");
164
+ assert(/source-grounded editable slide source/i.test(slidesProfile.prompt), "slides profile does not require grounded editable source");
165
+ assert(/render every slide/i.test(slidesProfile.prompt), "slides profile does not require full rendered inspection");
166
+ assert(/wrapped-title decoration overlap/i.test(slidesProfile.prompt), "slides profile does not guard wrapped-title collisions");
167
+ assert(/fresh git status --short/i.test(slidesProfile.prompt), "slides profile does not require fresh repository evidence");
162
168
  assert(
163
169
  capabilities.trustedDockerPolicy.some((check) => check.command.startsWith("apt-get install") && check.allowed),
164
170
  "trusted Docker policy did not allow apt-get install"
@@ -8,6 +8,7 @@ import {
8
8
  genericArtifactFilenameBlock,
9
9
  modelTimeoutExhaustionRoute,
10
10
  modelTimeoutRetryRoute,
11
+ normalizeNoMatchQueryResult,
11
12
  applyModelTimeoutRetryRoute,
12
13
  recoverFocusedTextRewriteWithWritingSpecialist,
13
14
  repairModelMessageHistory,
@@ -956,6 +957,33 @@ try {
956
957
  );
957
958
  assert(readonlyVersionPipelinePolicy.allowed, "read-only version probe pipelines should not require package-install-policy=allow");
958
959
  assert(readonlyVersionPipelinePolicy.category === "read-only", "read-only version probe pipelines should be classified as read-only");
960
+ const pgrepNoMatchPolicy = evaluateCommandPolicy(
961
+ "pgrep -af gateway_service",
962
+ dockerWorkspaceNoInstallsPolicy
963
+ );
964
+ assert(
965
+ pgrepNoMatchPolicy.allowed &&
966
+ pgrepNoMatchPolicy.category === "read-only" &&
967
+ pgrepNoMatchPolicy.noMatchExitIsSuccess === true,
968
+ "pgrep should be a read-only query whose no-match exit is meaningful evidence"
969
+ );
970
+ const pgrepNoMatchResult = normalizeNoMatchQueryResult(
971
+ { ok: false, exitCode: 1, stdout: "", stderr: "" },
972
+ pgrepNoMatchPolicy
973
+ );
974
+ assert(
975
+ pgrepNoMatchResult.ok === true &&
976
+ pgrepNoMatchResult.noMatch === true &&
977
+ pgrepNoMatchResult.semanticOutcome === "no-match",
978
+ "pgrep exit 1 with no diagnostics should normalize to successful no-match evidence"
979
+ );
980
+ assert(
981
+ normalizeNoMatchQueryResult(
982
+ { ok: false, exitCode: 2, stdout: "", stderr: "invalid option" },
983
+ pgrepNoMatchPolicy
984
+ ).ok === false,
985
+ "an actual pgrep error was incorrectly normalized as no-match evidence"
986
+ );
959
987
  const readonlyDiffSlicePolicy = evaluateCommandPolicy(
960
988
  "git diff -- src/agent-runner.js | sed -n '1,240p'",
961
989
  dockerWorkspaceNoInstallsPolicy
@@ -1000,6 +1028,16 @@ try {
1000
1028
  );
1001
1029
  assert(pythonUnittestPolicy.allowed, "stdlib python unittest should be allowed without package installs");
1002
1030
  assert(pythonUnittestPolicy.category === "test", "stdlib python unittest should be classified as test");
1031
+ const pythonNoBytecodeAcceptancePolicy = evaluateCommandPolicy(
1032
+ "PYTHONDONTWRITEBYTECODE=1 python3 /tmp/devops_sensor_gateway_contract.py",
1033
+ dockerWorkspaceNoInstallsPolicy
1034
+ );
1035
+ assert(
1036
+ pythonNoBytecodeAcceptancePolicy.allowed &&
1037
+ pythonNoBytecodeAcceptancePolicy.category === "test" &&
1038
+ pythonNoBytecodeAcceptancePolicy.substantiveTest === true,
1039
+ "a no-bytecode Python acceptance command should retain substantive test classification"
1040
+ );
1003
1041
  const pythonDemoPolicy = evaluateCommandPolicy("python3 demo.py 2>&1", dockerWorkspaceNoInstallsPolicy);
1004
1042
  assert(pythonDemoPolicy.allowed, "workspace-local python demo script should be allowed without package installs");
1005
1043
  assert(pythonDemoPolicy.category === "toolchain", "workspace-local python demo script should be classified as toolchain");
@@ -60,6 +60,7 @@ import {
60
60
  completionExternalBlockerCanClose,
61
61
  pythonTopLevelDefinitionDuplicates,
62
62
  recordCanonicalGeneratedOutputProgress,
63
+ recordAlreadyCommittedRepositoryRepair,
63
64
  recordProjectVerificationOutcome,
64
65
  recordExactOutputProgress,
65
66
  recordStaticDiscoveryProgress,
@@ -2095,6 +2096,36 @@ try {
2095
2096
  }
2096
2097
  );
2097
2098
  assert(coveredTestQuality.ok === true, coveredTestQuality.reason);
2099
+ const coveredBeforeAcceptanceQuality = await validateMutatedPythonSourceQuality(
2100
+ { commandCwd: pythonQualityWorkspace },
2101
+ {
2102
+ meta: {
2103
+ projectVerification: {
2104
+ mutationRevision: 3,
2105
+ privateMutationRevision: 0,
2106
+ mutationHistory: [{ revision: 3, paths: ["tests/test_service_launch.py"] }],
2107
+ testRuns: [
2108
+ {
2109
+ command: "PYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s tests -v",
2110
+ mutationRevision: 3,
2111
+ privateMutationRevision: 0,
2112
+ passed: true,
2113
+ },
2114
+ {
2115
+ command: "python3 /tmp/project_acceptance.py",
2116
+ mutationRevision: 3,
2117
+ privateMutationRevision: 0,
2118
+ passed: true,
2119
+ },
2120
+ ],
2121
+ },
2122
+ },
2123
+ }
2124
+ );
2125
+ assert(
2126
+ coveredBeforeAcceptanceQuality.ok === true,
2127
+ "a later passing acceptance verifier erased current unit-suite coverage for a changed test"
2128
+ );
2098
2129
  assert(normalizeDynamicStepsMode("off") === "off", "dynamic mode off did not normalize");
2099
2130
  for (const command of [
2100
2131
  "npm run build",
@@ -6136,6 +6167,124 @@ try {
6136
6167
  ) === null,
6137
6168
  "a clean-worktree verification gate could not rerun after a Git-state repair"
6138
6169
  );
6170
+ const successfulRepositoryRepairState = structuredClone(repositoryCleanGateFailure);
6171
+ successfulRepositoryRepairState.goal = "Repair and verify the service lifecycle.";
6172
+ successfulRepositoryRepairState.meta.goalContract = { revision: 4 };
6173
+ successfulRepositoryRepairState.meta.activeExecutionContract = {
6174
+ revision: 4,
6175
+ materialMutationRevision: 6,
6176
+ };
6177
+ const successfulRepositoryCommit = {
6178
+ toolName: "run_command",
6179
+ ok: true,
6180
+ exitCode: 0,
6181
+ args: {
6182
+ command:
6183
+ "git add -- 'gateway_service.py' && git commit -m 'Repair service lifecycle'",
6184
+ },
6185
+ stdout:
6186
+ "[main abcdef1] Repair service lifecycle\n 1 file changed, 1 insertion(+), 1 deletion(-)\n",
6187
+ stderr: "",
6188
+ };
6189
+ recordProjectVerificationOutcome(
6190
+ successfulRepositoryRepairState,
6191
+ successfulRepositoryCommit,
6192
+ { commandCwd: workspace, taskProfile: "devops" }
6193
+ );
6194
+ const successfulRepositoryRepairMarker = recordAlreadyCommittedRepositoryRepair(
6195
+ successfulRepositoryRepairState,
6196
+ successfulRepositoryCommit
6197
+ );
6198
+ const postCommitRepositoryRuntime = nextStepRuntimeConfig(
6199
+ { provider: "deepseek", taskProfile: "devops", commandCwd: workspace },
6200
+ successfulRepositoryRepairState
6201
+ );
6202
+ assert(
6203
+ successfulRepositoryRepairMarker?.source === "successful-commit" &&
6204
+ postCommitRepositoryRuntime.testFailureRepositoryStateRepair !== true &&
6205
+ postCommitRepositoryRuntime.testVerificationPending === true &&
6206
+ postCommitRepositoryRuntime.testVerificationCommand === failedValidationCommand,
6207
+ "a successful bounded repair commit did not advance directly to the exact failed verifier"
6208
+ );
6209
+ const cleanStatusRepositoryRepairState = structuredClone(repositoryCleanGateFailure);
6210
+ cleanStatusRepositoryRepairState.goal = "Resume the committed service repair.";
6211
+ cleanStatusRepositoryRepairState.meta.goalContract = { revision: 5 };
6212
+ cleanStatusRepositoryRepairState.meta.activeExecutionContract = {
6213
+ revision: 5,
6214
+ startedMutationRevision: 6,
6215
+ materialMutationRevision: 6,
6216
+ requiresFileMutation: true,
6217
+ requiresSourceGrounding: true,
6218
+ };
6219
+ cleanStatusRepositoryRepairState.meta.durableGitEvidence = [{
6220
+ action: "commit",
6221
+ goalRevision: 5,
6222
+ mutationRevision: 5,
6223
+ }];
6224
+ const cleanStatusAfterCommit = {
6225
+ toolName: "run_command",
6226
+ ok: true,
6227
+ exitCode: 0,
6228
+ args: { command: "git status --short" },
6229
+ stdout: "",
6230
+ stderr: "",
6231
+ };
6232
+ recordProjectVerificationOutcome(
6233
+ cleanStatusRepositoryRepairState,
6234
+ cleanStatusAfterCommit,
6235
+ { commandCwd: workspace, taskProfile: "devops" }
6236
+ );
6237
+ const cleanStatusRepositoryRepairMarker = recordAlreadyCommittedRepositoryRepair(
6238
+ cleanStatusRepositoryRepairState,
6239
+ cleanStatusAfterCommit
6240
+ );
6241
+ const cleanStatusRepositoryRuntime = nextStepRuntimeConfig(
6242
+ { provider: "deepseek", taskProfile: "devops", commandCwd: workspace },
6243
+ cleanStatusRepositoryRepairState
6244
+ );
6245
+ assert(
6246
+ cleanStatusRepositoryRepairMarker?.source === "clean-status-after-commit" &&
6247
+ cleanStatusRepositoryRuntime.completionFreshMutationRequired !== true &&
6248
+ cleanStatusRepositoryRuntime.testVerificationPending === true &&
6249
+ cleanStatusRepositoryRuntime.testVerificationCommand === failedValidationCommand &&
6250
+ buildKnownConstrainedPhasePlan(
6251
+ { provider: "deepseek", taskProfile: "devops", commandCwd: workspace },
6252
+ cleanStatusRepositoryRepairState,
6253
+ cleanStatusRepositoryRuntime
6254
+ )?.mode === "exact-verification",
6255
+ "current commit plus an exact clean Git status did not recover an interrupted repository repair"
6256
+ );
6257
+ const repeatedDirtyRepositoryResult = {
6258
+ toolName: "run_command",
6259
+ ok: false,
6260
+ exitCode: 1,
6261
+ args: { command: failedValidationCommand },
6262
+ stdout: "",
6263
+ stderr:
6264
+ "AssertionError: repository worktree is not clean after a new unrelated mutation",
6265
+ };
6266
+ recordProjectVerificationOutcome(
6267
+ successfulRepositoryRepairState,
6268
+ repeatedDirtyRepositoryResult,
6269
+ {
6270
+ provider: "deepseek",
6271
+ taskProfile: "devops",
6272
+ commandCwd: workspace,
6273
+ testVerificationPending: true,
6274
+ testVerificationCommand: failedValidationCommand,
6275
+ }
6276
+ );
6277
+ const repeatedDirtyRepositoryRuntime = nextStepRuntimeConfig(
6278
+ { provider: "deepseek", taskProfile: "devops", commandCwd: workspace },
6279
+ successfulRepositoryRepairState
6280
+ );
6281
+ assert(
6282
+ repeatedDirtyRepositoryResult.repositoryStateRepairConsumed === true &&
6283
+ !successfulRepositoryRepairState.meta.repositoryStateRepair &&
6284
+ repeatedDirtyRepositoryRuntime.testFailureRepositoryStateRepair === true &&
6285
+ repeatedDirtyRepositoryRuntime.testVerificationPending !== true,
6286
+ "a consumed repository-repair marker caused an unchanged clean-worktree verifier loop"
6287
+ );
6139
6288
  const oversizedRepositoryState = {
6140
6289
  ...repositoryCleanGateFailure,
6141
6290
  goal: "Complete the current repository task and preserve its established acceptance contract.",
@@ -6599,6 +6748,32 @@ try {
6599
6748
  projectTestVerificationFinishBlock(repairedValidationState) === null,
6600
6749
  "a passing rerun at the current real mutation revision did not reopen completion"
6601
6750
  );
6751
+ const presentationWrappedValidationState = {
6752
+ meta: {
6753
+ projectVerification: {
6754
+ mutationRevision: 7,
6755
+ privateMutationRevision: 0,
6756
+ testRuns: [
6757
+ {
6758
+ command: "python3 -m unittest discover -s tests -v 2>&1",
6759
+ mutationRevision: 2,
6760
+ privateMutationRevision: 0,
6761
+ passed: false,
6762
+ },
6763
+ {
6764
+ command: "PYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s tests -v",
6765
+ mutationRevision: 7,
6766
+ privateMutationRevision: 0,
6767
+ passed: true,
6768
+ },
6769
+ ],
6770
+ },
6771
+ },
6772
+ };
6773
+ assert(
6774
+ projectTestVerificationFinishBlock(presentationWrappedValidationState) === null,
6775
+ "presentation-only test wrappers left a superseded failure unresolved"
6776
+ );
6602
6777
  const tracebackEvidence = compactFailedTestEvidence(
6603
6778
  {
6604
6779
  stderr: [
@@ -68,6 +68,14 @@ const recoveryInstructionContract = deriveScsTaskContract({
68
68
  taskProfile: "devops",
69
69
  });
70
70
 
71
+ const readOnlyVerificationContinuationContract = deriveScsTaskContract({
72
+ goal: [
73
+ "Continue the exact active DevOps task from its clean committed state. Do not mutate source, tests, or documentation and do not create another commit.",
74
+ "Run exactly `git status --short` once, then follow the runtime's exact required verification commands serially. These include `PYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s tests -v` and `PYTHONDONTWRITEBYTECODE=1 python3 /tmp/devops_sensor_gateway_contract.py`.",
75
+ ].join("\n"),
76
+ taskProfile: "devops",
77
+ });
78
+
71
79
  const readOnlyReviewContract = deriveScsTaskContract({
72
80
  goal: [
73
81
  "Review focus: changed files only.",
@@ -171,6 +179,25 @@ assert.deepEqual(
171
179
  ],
172
180
  "a verification command introduced by 'followed by' was not retained"
173
181
  );
182
+ assert.deepEqual(
183
+ readOnlyVerificationContinuationContract.exactOutputPaths,
184
+ [],
185
+ "a verifier command following a negated create clause became an exact output path"
186
+ );
187
+ assert.deepEqual(
188
+ readOnlyVerificationContinuationContract.exactInputPaths,
189
+ [],
190
+ "a quoted verifier command became an exact input path"
191
+ );
192
+ assert.deepEqual(
193
+ readOnlyVerificationContinuationContract.requiredProjectCommands,
194
+ [
195
+ "git status --short",
196
+ "PYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s tests -v",
197
+ "PYTHONDONTWRITEBYTECODE=1 python3 /tmp/devops_sensor_gateway_contract.py",
198
+ ],
199
+ "an exact read-only continuation lost one or more required verification commands"
200
+ );
174
201
  assert.equal(
175
202
  readOnlyReviewContract.requiresWorkspaceMutation,
176
203
  false,
@@ -115,6 +115,11 @@ assert(selectedIds("write SQL migrations for sqlite schema").includes("database"
115
115
  assert(selectedIds("debug Docker deployment logs and port config").includes("devops-deployment"), "devops prompt did not select devops-deployment");
116
116
  assert(selectedIds("review auth security and secrets handling").includes("security-review"), "security prompt did not select security-review");
117
117
  assert(selectedIds("make a PowerPoint pitch deck").includes("presentation-slides"), "slides prompt did not select presentation-slides");
118
+ const presentationSkill = skills.find((skill) => skill.id === "presentation-slides");
119
+ assert(presentationSkill?.body.includes("Render every slide"), "presentation skill does not require every slide to be rendered");
120
+ assert(presentationSkill?.body.includes("wrapped titles"), "presentation skill does not require wrapped-title inspection");
121
+ assert(presentationSkill?.body.includes("git status --short"), "presentation skill does not require final repository evidence");
122
+ assert(presentationSkill?.body.includes("Do not call the deck complete"), "presentation skill still permits build-only completion");
118
123
  assert(selectedIds("edit a markdown screenplay final draft").includes("writing-editing"), "writing prompt did not select writing-editing");
119
124
  assert(selectedIds("create a lesson with exercises and quiz").includes("education-tutorial"), "education prompt did not select education-tutorial");
120
125
  assert(selectedIds("review this PR architecture without editing").includes("code-review"), "review prompt did not select code-review");
@@ -20,7 +20,17 @@ tools:
20
20
  ---
21
21
  # Slides And Presentations
22
22
 
23
- Clarify audience, goal, length, and tone from context. Build a durable outline before slide text. Keep slides visually sparse: one message, one figure/table/story per slide when possible.
23
+ Infer audience, goal, length, and tone from the request and available project context. Ask only when a missing fact materially changes the deck. Build a durable outline before slide text. Keep slides visually sparse: one message and usually one figure, table, or story per slide.
24
24
 
25
- Use markdown, HTML, LaTeX beamer, PPTX tooling, or available local converters depending on the workspace. Save source plus exported artifacts when possible.
25
+ Use the workspace's established presentation tooling when it exists. Otherwise choose editable PPTX, HTML, Markdown, or LaTeX Beamer tooling that can be rebuilt locally. Keep essential titles, claims, labels, citations, and body text editable. Image generation may supply bounded visual assets, but never use one generated bitmap as a complete slide or slide background.
26
26
 
27
+ Ground claims and calculations in the supplied sources. Preserve a reproducible source or build script and speaker notes when they improve delivery. Produce only the requested artifacts, with descriptive stable filenames. If the user supplied an exact validator or acceptance command, run that exact command after the final rebuild.
28
+
29
+ Before completion:
30
+
31
+ 1. Rebuild the final deck and every requested export from the current source.
32
+ 2. Render every slide to a PNG or equivalent preview and inspect the actual images. Check especially wrapped titles, accent rules, clipping, collisions, overflow, unreadably small text, charts, tables, and consistent framing.
33
+ 3. Verify that the PPTX or source remains editable, exported files open, slide and PDF page counts agree, calculations match the source data, and no unsupported claims were introduced.
34
+ 4. In a Git repository, if the task requests a commit, stage intentional source and deliverables, narrowly ignore only transient build or perception evidence, commit the result, then run a fresh `git status --short`.
35
+
36
+ Do not call the deck complete from a successful build alone. Artifact paths, model-generated visual descriptions, or an earlier clean status are not substitutes for current rendered inspection and final external verification.
@@ -84,6 +84,7 @@ import {
84
84
  buildPermissionAdvice,
85
85
  goalRevisionCoversActiveTask,
86
86
  isAlreadyCommittedCleanGitNoop,
87
+ isCleanGitStatusAfterCurrentCommit,
87
88
  } from "./permission-advice.js";
88
89
  import { formatBehaviorContractForPrompt } from "./behavior-contract.js";
89
90
  import { browserStateReconciliationGuidance } from "./browser-automation-guidance.js";
@@ -4295,6 +4296,23 @@ export function shellDiagnosticHint(command = "", result = {}) {
4295
4296
  return "";
4296
4297
  }
4297
4298
 
4299
+ export function normalizeNoMatchQueryResult(result = {}, policy = {}) {
4300
+ if (
4301
+ policy?.noMatchExitIsSuccess !== true ||
4302
+ Number(result?.exitCode) !== 1 ||
4303
+ String(result?.stdout || "").trim() ||
4304
+ String(result?.stderr || "").trim()
4305
+ ) {
4306
+ return result;
4307
+ }
4308
+ return {
4309
+ ...result,
4310
+ ok: true,
4311
+ noMatch: true,
4312
+ semanticOutcome: "no-match",
4313
+ };
4314
+ }
4315
+
4298
4316
  function hashForLog(value) {
4299
4317
  return crypto.createHash("sha256").update(String(value ?? "")).digest("hex");
4300
4318
  }
@@ -6142,6 +6160,21 @@ export function recordProjectVerificationOutcome(state = {}, toolResult = {}, co
6142
6160
  requiredCommandFailure: failedRequiredCommand,
6143
6161
  ...failedEvidence,
6144
6162
  };
6163
+ const repositoryStateRepairMarker = state.meta?.repositoryStateRepair;
6164
+ if (
6165
+ repositoryStateRepairMarker &&
6166
+ Number(repositoryStateRepairMarker.version || 0) === 1 &&
6167
+ Number(repositoryStateRepairMarker.mutationRevision || 0) ===
6168
+ verification.mutationRevision &&
6169
+ projectTestCommandKey(repositoryStateRepairMarker.command || "") ===
6170
+ projectTestCommandKey(command)
6171
+ ) {
6172
+ // A repository repair authorizes one exact verifier rerun. Consume the
6173
+ // marker so a still-dirty worktree returns to repair instead of
6174
+ // replaying the same verifier indefinitely.
6175
+ delete state.meta.repositoryStateRepair;
6176
+ toolResult.repositoryStateRepairConsumed = true;
6177
+ }
6145
6178
  verification.testRuns = [...verification.testRuns, testRun].slice(-24);
6146
6179
  toolResult.projectTest = testRun;
6147
6180
  if (
@@ -6243,13 +6276,19 @@ export function failedTestRequiresCleanRepositoryState(testRun = {}) {
6243
6276
  }
6244
6277
 
6245
6278
  export function recordAlreadyCommittedRepositoryRepair(state = {}, toolResult = {}) {
6246
- if (
6247
- !isAlreadyCommittedCleanGitNoop(
6248
- toolResult.args || {},
6249
- toolResult,
6250
- state
6251
- )
6252
- ) {
6279
+ const successfulCommit = inferSuccessfulGitActionsFromCommandResult(toolResult)
6280
+ .includes("commit");
6281
+ const cleanCommitNoop = isAlreadyCommittedCleanGitNoop(
6282
+ toolResult.args || {},
6283
+ toolResult,
6284
+ state
6285
+ );
6286
+ const cleanStatusAfterCommit = isCleanGitStatusAfterCurrentCommit(
6287
+ toolResult.args || {},
6288
+ toolResult,
6289
+ state
6290
+ );
6291
+ if (!successfulCommit && !cleanCommitNoop && !cleanStatusAfterCommit) {
6253
6292
  return null;
6254
6293
  }
6255
6294
  const failed = currentFailedProjectTest(state);
@@ -6266,7 +6305,11 @@ export function recordAlreadyCommittedRepositoryRepair(state = {}, toolResult =
6266
6305
  ),
6267
6306
  failureSignature: String(failed.test.failureSignature || ""),
6268
6307
  command: String(failed.test.command || ""),
6269
- source: "clean-commit-noop",
6308
+ source: successfulCommit
6309
+ ? "successful-commit"
6310
+ : cleanCommitNoop
6311
+ ? "clean-commit-noop"
6312
+ : "clean-status-after-commit",
6270
6313
  at: new Date().toISOString(),
6271
6314
  };
6272
6315
  state.meta.repositoryStateRepair = marker;
@@ -6277,7 +6320,13 @@ export function recordAlreadyCommittedRepositoryRepair(state = {}, toolResult =
6277
6320
  function projectTestCommandKey(command = "") {
6278
6321
  const normalized = normalizeProjectCommand(command);
6279
6322
  const exitProbe = parseNonMutatingExitStatusWrapper(normalized);
6280
- return normalizeProjectCommand(exitProbe?.command || normalized);
6323
+ const invocation = normalizeProjectCommand(exitProbe?.command || normalized)
6324
+ // These wrappers alter bytecode/output handling, not the tests selected or
6325
+ // executed. Treating them as distinct suites can leave an old failure
6326
+ // unresolved after the same verifier passes without the wrapper.
6327
+ .replace(/^PYTHONDONTWRITEBYTECODE=(?:0|1|true|false)\s+/i, "")
6328
+ .replace(/\s+(?:2>&1|1>&2)\s*$/u, "");
6329
+ return normalizeProjectCommand(invocation);
6281
6330
  }
6282
6331
 
6283
6332
  function commandIncludesGitCommit(command = "") {
@@ -11509,6 +11558,11 @@ export function nextStepRuntimeConfig(config = {}, state = {}) {
11509
11558
  runtimeConfig.repositoryStateRepairCommitPaths =
11510
11559
  taskOwnedMutationPathsSinceLatestCommit(verification);
11511
11560
  } else if (retainedRepositoryStateRepair) {
11561
+ delete runtimeConfig.completionFreshMutationRequired;
11562
+ delete runtimeConfig.completionFreshMutationRevision;
11563
+ delete runtimeConfig.completionFreshMutationPaths;
11564
+ delete runtimeConfig.completionFreshMutationNeedsSourceRead;
11565
+ delete runtimeConfig.repositoryGroundingRequired;
11512
11566
  runtimeConfig.testFailureRepairActive = false;
11513
11567
  runtimeConfig.testFailureRepairMutationRequired = false;
11514
11568
  runtimeConfig.testFailureRepairNeedsPatchContext = false;
@@ -13560,23 +13614,26 @@ async function runShellCommand(command, config, policy = evaluateCommandPolicy(c
13560
13614
  const result = config.useDockerSandbox
13561
13615
  ? await runDockerSandboxCommand(command, config, policy, { signal: config.abortSignal })
13562
13616
  : await runHostShellCommand(command, config);
13563
- const diagnosticHint = shellDiagnosticHint(command, result);
13617
+ const normalizedResult = normalizeNoMatchQueryResult(result, policy);
13618
+ const diagnosticHint = shellDiagnosticHint(command, normalizedResult);
13564
13619
 
13565
13620
  return {
13566
- ok: result.ok !== false,
13567
- exitCode: Number.isInteger(result.exitCode) ? result.exitCode : 0,
13568
- stdout: trimCommandOutput(result.stdout, 8000),
13569
- stderr: trimCommandOutput(result.stderr, 4000),
13621
+ ok: normalizedResult.ok !== false,
13622
+ exitCode: Number.isInteger(normalizedResult.exitCode) ? normalizedResult.exitCode : 0,
13623
+ stdout: trimCommandOutput(normalizedResult.stdout, 8000),
13624
+ stderr: trimCommandOutput(normalizedResult.stderr, 4000),
13625
+ ...(normalizedResult.noMatch === true ? { noMatch: true, semanticOutcome: "no-match" } : {}),
13570
13626
  ...(diagnosticHint ? { diagnosticHint } : {}),
13571
13627
  };
13572
13628
  } catch (error) {
13573
13629
  if (isAbortError(error, config)) throw error;
13574
- const failedResult = {
13630
+ const rawFailedResult = {
13575
13631
  ok: false,
13576
13632
  exitCode: Number.isInteger(error?.code) ? error.code : 1,
13577
13633
  stdout: trimCommandOutput(error?.stdout || "", 8000),
13578
13634
  stderr: trimCommandOutput(error?.stderr || error?.message || "", 4000),
13579
13635
  };
13636
+ const failedResult = normalizeNoMatchQueryResult(rawFailedResult, policy);
13580
13637
  const diagnosticHint = shellDiagnosticHint(command, failedResult);
13581
13638
  return diagnosticHint ? { ...failedResult, diagnosticHint } : failedResult;
13582
13639
  }
@@ -14656,6 +14713,7 @@ async function executeTool(browserState, toolCall, snapshot, config, store, obse
14656
14713
  mayMutateProject: Boolean(policy.mayMutateProject),
14657
14714
  substantiveTest: Boolean(policy.substantiveTest),
14658
14715
  gitOnly: Boolean(policy.gitOnly),
14716
+ noMatchExitIsSuccess: Boolean(policy.noMatchExitIsSuccess),
14659
14717
  normalizedCommand: normalizeCommandForPolicy(String(args.command), config),
14660
14718
  },
14661
14719
  ...(generatedOutputPaths.length
@@ -15551,13 +15609,13 @@ export async function validateMutatedPythonSourceQuality(config = {}, state = {}
15551
15609
 
15552
15610
  const defects = [];
15553
15611
  const checkedPaths = [];
15554
- const latestPassingTest = [...(Array.isArray(verification.testRuns) ? verification.testRuns : [])]
15612
+ const currentPassingTests = [...(Array.isArray(verification.testRuns) ? verification.testRuns : [])]
15555
15613
  .reverse()
15556
- .find(
15614
+ .filter(
15557
15615
  (run) =>
15558
15616
  run?.passed === true &&
15559
- Number(run?.mutationRevision || 0) === Math.max(0, Number(verification.mutationRevision || 0)) &&
15560
- Number(run?.privateMutationRevision || 0) === verificationPrivateMutationRevision(verification)
15617
+ !testRunRepresentsInvalidInvocation(run) &&
15618
+ testRunMatchesVerificationRevision(run, verification)
15561
15619
  );
15562
15620
  for (const sourcePath of paths) {
15563
15621
  let target;
@@ -15577,14 +15635,14 @@ export async function validateMutatedPythonSourceQuality(config = {}, state = {}
15577
15635
  message: syntax.reason,
15578
15636
  });
15579
15637
  }
15580
- if (
15581
- pathLooksLikeTestSource(sourcePath) &&
15582
- (!latestPassingTest || !testCommandCoversMutatedPath(latestPassingTest.command, sourcePath))
15583
- ) {
15638
+ const coveringTest = pathLooksLikeTestSource(sourcePath)
15639
+ ? currentPassingTests.find((run) => testCommandCoversMutatedPath(run.command, sourcePath))
15640
+ : null;
15641
+ if (pathLooksLikeTestSource(sourcePath) && !coveringTest) {
15584
15642
  defects.push({
15585
15643
  code: "mutated-test-not-covered-by-validation",
15586
15644
  path: sourcePath,
15587
- command: String(latestPassingTest?.command || ""),
15645
+ command: String(currentPassingTests[0]?.command || ""),
15588
15646
  });
15589
15647
  }
15590
15648
  for (const duplicate of pythonTopLevelDefinitionDuplicates(content)) {
@@ -15610,7 +15668,7 @@ export async function validateMutatedPythonSourceQuality(config = {}, state = {}
15610
15668
  item.code === "python-syntax-error"
15611
15669
  ? `${item.path}: ${item.message || "Python syntax validation failed"}`
15612
15670
  : item.code === "mutated-test-not-covered-by-validation"
15613
- ? `${item.path}: the latest successful test command did not include this changed test (${item.command || "no current test command"})`
15671
+ ? `${item.path}: no current successful test command included this changed test (${item.command || "no current test command"})`
15614
15672
  : item.code === "python-main-guard-before-required-definition"
15615
15673
  ? `${item.path}: __main__ guard at line ${item.guardLine} executes before ` +
15616
15674
  `${(item.calledLater || []).map((candidate) => `${candidate.name} at line ${candidate.line}`).join(", ")}`
@@ -20,6 +20,7 @@ const READ_ONLY_PATTERNS = [
20
20
  /^find(?:\s+[./~\w-]+)*(?:\s+-maxdepth\s+\d+)?(?:\s+-type\s+[fd])?$/,
21
21
  /^rg(?:\s+.+)?$/,
22
22
  /^grep(?:\s+.+)?$/,
23
+ /^pgrep(?:\s+.+)?$/,
23
24
  /^cat(?:\s+[-\w./~*]+)+$/,
24
25
  /^head(?:\s+.+)?$/,
25
26
  /^tail(?:\s+.+)?$/,
@@ -751,7 +752,14 @@ function classifyBackgroundShell(normalized = "") {
751
752
  const SAFE_WORKSPACE_WRITE_PATTERNS = [/^mkdir\s+-p\s+[-\w./]+$/];
752
753
  const SAFE_CHMOD_MODE_PATTERN = /^[-+=,rwxugoXst0-7]+$/;
753
754
  const SAFE_WORKSPACE_TARGET_LIMIT = 64;
754
- const SAFE_ENV_ASSIGNMENT_NAMES = new Set(["ANDROID_HOME", "ANDROID_SDK_ROOT", "JAVA_HOME", "GRADLE_USER_HOME", "PATH"]);
755
+ const SAFE_ENV_ASSIGNMENT_NAMES = new Set([
756
+ "ANDROID_HOME",
757
+ "ANDROID_SDK_ROOT",
758
+ "GRADLE_USER_HOME",
759
+ "JAVA_HOME",
760
+ "PATH",
761
+ "PYTHONDONTWRITEBYTECODE",
762
+ ]);
755
763
  const SAFE_ENV_VALUE_PATTERN = /^[-\w./:@+,%]+$/;
756
764
 
757
765
  const NETWORK_FETCH_PATTERNS = [
@@ -1681,6 +1689,7 @@ function classifySimpleCommand(normalized) {
1681
1689
  needsNetwork: false,
1682
1690
  writesWorkspace: false,
1683
1691
  gitOnly: /^git\s+/.test(commandForPatternMatching),
1692
+ noMatchExitIsSuccess: /^pgrep\b/.test(commandForPatternMatching),
1684
1693
  };
1685
1694
  }
1686
1695
  const packageScript = packageManagerScriptName(validationTokens);
@@ -615,6 +615,44 @@ export function goalRevisionCoversActiveTask(state = {}, evidenceRevision = 0) {
615
615
  return candidateRevision >= activeTaskStartRevision;
616
616
  }
617
617
 
618
+ function hasDurableCommitEvidence(state = {}, { requireCurrentMutation = true } = {}) {
619
+ const mutationRevision = Math.max(
620
+ 0,
621
+ Number(state.meta?.projectVerification?.mutationRevision || 0)
622
+ );
623
+ return (Array.isArray(state.meta?.durableGitEvidence) ? state.meta.durableGitEvidence : []).some(
624
+ (item) =>
625
+ String(item?.action || "").toLowerCase() === "commit" &&
626
+ goalRevisionCoversActiveTask(state, item?.goalRevision) &&
627
+ (
628
+ !requireCurrentMutation ||
629
+ Number(item?.mutationRevision || 0) >= mutationRevision
630
+ )
631
+ );
632
+ }
633
+
634
+ export function isCleanGitStatusAfterCurrentCommit(args = {}, result = {}, state = {}) {
635
+ const command = String(args.command || args.text || "").trim();
636
+ const cleanStatusCommand =
637
+ /^git(?:\s+-C\s+(?:"[^"]*"|'[^']*'|\S+))?\s+status\s+(?:--short|--porcelain(?:=[^\s]+)?)(?:\s+--untracked-files=(?:all|normal))?$/i.test(
638
+ command
639
+ );
640
+ if (
641
+ !cleanStatusCommand ||
642
+ result.ok === false ||
643
+ Number(result.exitCode ?? 0) !== 0 ||
644
+ String(result.stdout || "").trim() ||
645
+ String(result.stderr || "").trim()
646
+ ) {
647
+ return false;
648
+ }
649
+ // An exact clean status proves that the current files match HEAD. Permit a
650
+ // same-task commit from an earlier mutation revision so interrupted work
651
+ // that was externally restored to HEAD can return to its verifier. The
652
+ // verifier, not this marker, still decides task completion.
653
+ return hasDurableCommitEvidence(state, { requireCurrentMutation: false });
654
+ }
655
+
618
656
  export function isAlreadyCommittedCleanGitNoop(args = {}, result = {}, state = {}) {
619
657
  const command = String(args.command || args.text || "");
620
658
  const output = `${result.stdout || ""}\n${result.stderr || ""}`;
@@ -625,16 +663,7 @@ export function isAlreadyCommittedCleanGitNoop(args = {}, result = {}, state = {
625
663
  ) {
626
664
  return false;
627
665
  }
628
- const mutationRevision = Math.max(
629
- 0,
630
- Number(state.meta?.projectVerification?.mutationRevision || 0)
631
- );
632
- return (Array.isArray(state.meta?.durableGitEvidence) ? state.meta.durableGitEvidence : []).some(
633
- (item) =>
634
- String(item?.action || "").toLowerCase() === "commit" &&
635
- goalRevisionCoversActiveTask(state, item?.goalRevision) &&
636
- Number(item?.mutationRevision || 0) >= mutationRevision
637
- );
666
+ return hasDurableCommitEvidence(state);
638
667
  }
639
668
 
640
669
  export function buildFailedCommandAdvice({ args = {}, commandPolicy = {}, commandResult = {}, config = {}, state = {} } = {}) {
@@ -649,6 +649,7 @@ function inferExactInputPaths(goal = "") {
649
649
  }
650
650
  quotedPathPattern.lastIndex = 0;
651
651
  for (const match of line.matchAll(quotedPathPattern)) {
652
+ if (looksLikeShellCommandLiteral(match[1])) continue;
652
653
  pushPath(match[1]);
653
654
  }
654
655
  const unquotedLine = line.replace(quotedPathPattern, (match) => " ".repeat(match.length));
@@ -1379,12 +1380,36 @@ function prefixRequestsInlineCommandExecution(prefix = "") {
1379
1380
  while (preamble.test(clause)) clause = clause.replace(preamble, "").trim();
1380
1381
  clause = clause.replace(/(?:[::]|--?)\s*$/, "").trim();
1381
1382
  return (
1382
- /^(?:followed\s+by|run|rerun|re-run|execute|invoke|launch|verify|validate|check|confirm)(?:\s+(?:(?:the|this|that)\s+)?(?:following\s+)?command(?:\s+named)?)?\s*$/i.test(
1383
+ /^(?:followed\s+by|run|rerun|re-run|execute|invoke|launch|verify|validate|check|confirm)(?:\s+(?:exactly|again|once))?(?:\s+(?:(?:the|this|that)\s+)?(?:exact|required|following\s+)?command(?:\s+named)?)?\s*$/i.test(
1383
1384
  clause
1384
1385
  ) || /^(?:随后运行|隨後運行|接着运行|接著運行|运行|運行|执行|執行|调用|調用|验证|驗證|检查|檢查|确认|確認)\s*$/.test(clause)
1385
1386
  );
1386
1387
  }
1387
1388
 
1389
+ function sentenceContinuesRequestedCommandList(source = "", sentenceStart = -1, commandIndex = -1) {
1390
+ const prefix = String(source || "").slice(sentenceStart + 1, commandIndex).trim();
1391
+ if (!/^(?:these|those|the\s+following)\s+(?:commands?\s+)?(?:include|are)\b/i.test(prefix)) {
1392
+ return false;
1393
+ }
1394
+
1395
+ const preceding = String(source || "").slice(0, Math.max(0, sentenceStart)).trimEnd();
1396
+ const previousStart = Math.max(
1397
+ preceding.lastIndexOf("\n"),
1398
+ preceding.lastIndexOf("."),
1399
+ preceding.lastIndexOf("!"),
1400
+ preceding.lastIndexOf("?"),
1401
+ preceding.lastIndexOf("。"),
1402
+ preceding.lastIndexOf("!"),
1403
+ preceding.lastIndexOf("?")
1404
+ );
1405
+ const previousSentence = preceding.slice(previousStart + 1).trim();
1406
+ return (
1407
+ /\b(?:run|rerun|re-run|execute|invoke|launch|verify|validate|check|confirm|follow)\b/i.test(previousSentence) &&
1408
+ /\b(?:exact|required|following|verification|validation|test|check)\b/i.test(previousSentence) &&
1409
+ /\bcommands?\b/i.test(previousSentence)
1410
+ );
1411
+ }
1412
+
1388
1413
  function canonicalBareVerifierCommand(rawPath = "") {
1389
1414
  const candidate = String(rawPath || "").trim();
1390
1415
  if (
@@ -1439,7 +1464,12 @@ function inferExplicitRequestedCommands(goal = "") {
1439
1464
  source.lastIndexOf("?", index - 1)
1440
1465
  );
1441
1466
  const prefix = source.slice(sentenceStart + 1, index).trimEnd();
1442
- if (!prefixRequestsInlineCommandExecution(prefix)) continue;
1467
+ if (
1468
+ !prefixRequestsInlineCommandExecution(prefix) &&
1469
+ !sentenceContinuesRequestedCommandList(source, sentenceStart, index)
1470
+ ) {
1471
+ continue;
1472
+ }
1443
1473
 
1444
1474
  const command = normalizeProjectCommand(match[1]);
1445
1475
  if (
@@ -1487,7 +1517,7 @@ export function deriveScsTaskContract({ goal = "", taskProfile = "", acceptanceC
1487
1517
  }));
1488
1518
  const excludedOutputPaths = inferExplicitlyExcludedOutputPaths(evidenceGoal);
1489
1519
  const inferredOutputPaths = filterExplicitlyExcludedOutputPaths(
1490
- inferExactOutputPaths(evidenceGoal),
1520
+ inferExactOutputPaths(positiveEvidenceGoal),
1491
1521
  excludedOutputPaths
1492
1522
  );
1493
1523
  const exactOutputPaths = filterExplicitlyExcludedOutputPaths(
@@ -1515,7 +1545,7 @@ export function deriveScsTaskContract({ goal = "", taskProfile = "", acceptanceC
1515
1545
  requiresPerSourceChecks: requiresPerSourceChecks(evidenceGoal),
1516
1546
  requiredToolCalls,
1517
1547
  requiredGitActions,
1518
- requiredProjectCommands: inferExplicitRequestedCommands(evidenceGoal),
1548
+ requiredProjectCommands: inferExplicitRequestedCommands(positiveEvidenceGoal),
1519
1549
  requiresWorkspaceMutation: goalRequestsWorkspaceMutation(evidenceGoal, taskProfile),
1520
1550
  requiresFileMutation: goalRequestsFileMutation(evidenceGoal, taskProfile),
1521
1551
  requiresSourceGrounding: requiresSourceGrounding(evidenceGoal),
@@ -122,7 +122,7 @@ export const TASK_PROFILES = {
122
122
  id: "slides",
123
123
  label: "Slides and presentations",
124
124
  prompt:
125
- "Bias toward presentation, pitch deck, poster, lecture, and slide-style communication. Clarify audience and purpose from available context, create a durable outline and slide files or markdown deck, keep each slide visually focused, include speaker notes when useful, and export/preview when local tools support it.",
125
+ "Bias toward presentation, pitch deck, poster, lecture, and slide-style communication. Infer audience and purpose from available context, create a durable outline and source-grounded editable slide source, keep each slide visually focused, and include useful speaker notes. Preserve editable text, charts, tables, and shapes instead of flattening complete slides into images. Produce the requested deck/export formats and a reproducible build path when practical. Render every slide to a preview and inspect the actual pixels for clipping, collisions, wrapped-title decoration overlap, unreadable text, and inconsistent framing; rebuild after repairs. Verify source claims and calculations, artifact existence and package readability, slide/page counts across PPTX/PDF/previews, and any exact acceptance command supplied by the user. In a Git repository, when the task asks for a commit, commit intentional source and deliverables, narrowly ignore only transient build/perception evidence, and run a fresh git status --short before claiming completion.",
126
126
  tools: ["files", "shell", "canvas", "web_search"],
127
127
  },
128
128
  education: {