@tea-agent/loop-agent 0.38.1 → 0.39.0-beta.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.
Files changed (160) hide show
  1. package/CHANGELOG.md +115 -13
  2. package/README.md +2 -0
  3. package/dist/application/dag/generate-task-dag.js +9 -0
  4. package/dist/application/task-lifecycle/advance.js +4 -0
  5. package/dist/build-stamp.json +3 -3
  6. package/dist/commands/init.js +2 -14
  7. package/dist/commands/task-advance.js +31 -0
  8. package/dist/executors/dag-pi-executor.js +41 -4
  9. package/dist/executors/pi-event-serializer.js +42 -1
  10. package/dist/executors/pi-executor.js +51 -0
  11. package/dist/executors/pi-sdk-executor.js +7 -26
  12. package/dist/executors/shell-executor.js +270 -16
  13. package/dist/governance/manifest-types.js +0 -2
  14. package/dist/shared/operator/capabilities.js +87 -22
  15. package/dist/task/config-types.js +22 -0
  16. package/dist/task/contract/constants.js +1 -0
  17. package/dist/task/contract/diff.js +26 -0
  18. package/dist/task/contract/project.js +5 -0
  19. package/dist/task/contract/schema.js +6 -1
  20. package/dist/task/source-prepare/build-draft.js +15 -0
  21. package/dist/worker/console/chat/deferred-turn.js +91 -0
  22. package/dist/worker/console/chat/pi-runtime.js +10 -5
  23. package/dist/worker/console/chat/routes.js +458 -47
  24. package/dist/worker/console/chat/semantic-activity.js +13 -13
  25. package/dist/worker/console/chat/session-store.js +146 -2
  26. package/dist/worker/console/harness-pi-model-matrix.js +2 -11
  27. package/dist/worker/console/operator-actions.js +5 -4
  28. package/dist/worker/console/pi-readiness.js +5 -4
  29. package/dist/worker/console/recovery-cta.js +4 -4
  30. package/dist/worker/console/recovery-error-copy.js +4 -4
  31. package/dist/worker/console/server.js +6 -1
  32. package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-Hfsot6rP.js → abnfDiagram-N423BO3Z-C4kVYweA.js} +1 -1
  33. package/dist/worker/console/static/assets/{arc-YGwEASin.js → arc-Bj2M8iO5.js} +1 -1
  34. package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-CmOM0F92.js → architectureDiagram-T3A2C74G-CLlXe4-6.js} +1 -1
  35. package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-DDLuaHC5.js → blockDiagram-VBNYF7ZC-psEp5xH0.js} +1 -1
  36. package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-B0Um43W4.js → c4Diagram-5PPSVZJV-DeKcOCGJ.js} +1 -1
  37. package/dist/worker/console/static/assets/channel-CPF4N7pf.js +1 -0
  38. package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-DvBN4JZc.js → chunk-2GRJ4B5K-K0C744p1.js} +1 -1
  39. package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-B1UVgW4E.js → chunk-2Q5K7J3B-xbNw4J9-.js} +1 -1
  40. package/dist/worker/console/static/assets/{chunk-5RXB4S5H-Cf0GgXzX.js → chunk-5RXB4S5H-DjLaSDUO.js} +1 -1
  41. package/dist/worker/console/static/assets/{chunk-5VM5RSS4-DbNA24sj.js → chunk-5VM5RSS4-CtiPlKel.js} +1 -1
  42. package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-Bi_0Be06.js → chunk-6Q2QTUOP-DZtolir7.js} +1 -1
  43. package/dist/worker/console/static/assets/{chunk-GF5L2VYU-C8pPGvRd.js → chunk-GF5L2VYU-CPcdNeew.js} +1 -1
  44. package/dist/worker/console/static/assets/{chunk-JWPE2WC7-BitQY8Z-.js → chunk-JWPE2WC7-NgHc6V37.js} +1 -1
  45. package/dist/worker/console/static/assets/{chunk-KBJHAD2P-U67GCiEo.js → chunk-KBJHAD2P-DQ_T-hg8.js} +1 -1
  46. package/dist/worker/console/static/assets/{chunk-RYQCIY6F-IoJwXPBA.js → chunk-RYQCIY6F-DgLsxcVP.js} +1 -1
  47. package/dist/worker/console/static/assets/{chunk-XXDRQBXY-YDZ_UHgE.js → chunk-XXDRQBXY-UrVoM9z1.js} +1 -1
  48. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-C2DwA_Y1.js +1 -0
  49. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-C2DwA_Y1.js +1 -0
  50. package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-CUZgsiRC.js → cose-bilkent-JH36ORCC-CLkYvTb3.js} +1 -1
  51. package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-COmCh4pT.js → cynefin-VYW2F7L2-BwT_xKrE.js} +1 -1
  52. package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-Ta6FSm68.js → cynefinDiagram-MW4NZA55-Bi9tuzif.js} +1 -1
  53. package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-UdcR-VW9.js → dagre-VZM6K2ZE-BCIqkWBV.js} +1 -1
  54. package/dist/worker/console/static/assets/{diagram-7IWD3JNH-DybcO3Et.js → diagram-7IWD3JNH-Dip6l9_Z.js} +1 -1
  55. package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-wErDFWLw.js → diagram-B4RE2ZJO-B-xkh_wK.js} +1 -1
  56. package/dist/worker/console/static/assets/{diagram-LBJQPF4R-DkVHZWqz.js → diagram-LBJQPF4R-DZO0kTt_.js} +1 -1
  57. package/dist/worker/console/static/assets/{diagram-Q27KOJAE-DdqWs7QN.js → diagram-Q27KOJAE-D6ZplNbZ.js} +1 -1
  58. package/dist/worker/console/static/assets/{diagram-UB23O5K3-C9dMVmDo.js → diagram-UB23O5K3-BPekbhoS.js} +1 -1
  59. package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-B2T2WcBK.js → ebnfDiagram-BXEA7PRR-BtmaJpK5.js} +1 -1
  60. package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-Bt9rjDFq.js → erDiagram-JOGREHBK-6DS0Xc44.js} +1 -1
  61. package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-U8ic_tvi.js → flowDiagram-UKHOOZJN-CihnROSm.js} +1 -1
  62. package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-BfQJdQoO.js → ganttDiagram-PKOTCBZU-CZC4zOE2.js} +1 -1
  63. package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-CpMftH4O.js → gitGraphDiagram-DS77QQ5N-Dq1fhzGN.js} +1 -1
  64. package/dist/worker/console/static/assets/index-DTZOKgAn.js +404 -0
  65. package/dist/worker/console/static/assets/index-Ya5FE7cD.css +1 -0
  66. package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-DzqWXNO_.js → infoDiagram-6WML65LV-DlSl4BGx.js} +1 -1
  67. package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-CJmGQ5Yp.js → ishikawaDiagram-WSZJBQD7-snnzFl_U.js} +1 -1
  68. package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-ChPtKFLz.js → journeyDiagram-NVQOT4AX-BDE7qpMx.js} +1 -1
  69. package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-PRe7wB5u.js → kanban-definition-27J2QSJJ-CD2Ci04G.js} +1 -1
  70. package/dist/worker/console/static/assets/{linear-DpKX6QNp.js → linear-DdnapKIH.js} +1 -1
  71. package/dist/worker/console/static/assets/{mermaid.core-Dnl76b7Y.js → mermaid.core-BVjAT9b8.js} +5 -5
  72. package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-S9PCXc3J.js → mindmap-definition-FAOFIHXS-D0yJk-zA.js} +1 -1
  73. package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-Du8e-FSX.js → pegDiagram-VL7TDLO6-BVo9tFP-.js} +1 -1
  74. package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-CY6OmHTc.js → pieDiagram-7S7Q4E2Y-DnOV-mZ_.js} +1 -1
  75. package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-C65GPhpj.js → quadrantDiagram-CIZ2JOQS-CzUJo58i.js} +1 -1
  76. package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-U6IUiTCL.js → railroadDiagram-AXF67PYL-Bvikrolh.js} +1 -1
  77. package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-D-I_9Qhi.js → requirementDiagram-LRYGKXZP-DtaSVCap.js} +1 -1
  78. package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-B57Fhed0.js → sankeyDiagram-W5VNT64P-C2c9A0wW.js} +1 -1
  79. package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-CJOtiw21.js → sequenceDiagram-SI44F4Z6-DmXJcU7r.js} +1 -1
  80. package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-FyX8zxSh.js → sizeCapture-X5ZJPWSS-B4GUFW92.js} +1 -1
  81. package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-eF-pbs9t.js → stateDiagram-OKZ733FA-Dsad2MXf.js} +1 -1
  82. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-B8FB_cNk.js +1 -0
  83. package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-CcfkA-Dq.js → swimlanes-SLNWSIFB-DGq48Fbi.js} +2 -2
  84. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-CrZYaWfx.js +8 -0
  85. package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-DH8FjnOK.js → timeline-definition-Z64GVDOM-CSSi6OFf.js} +1 -1
  86. package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-beoTagJg.js → vennDiagram-T6HMQDX7-BqyzPrWv.js} +1 -1
  87. package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-CQSfw4cK.js → wardleyDiagram-T6FBY63Y-DlznVb6S.js} +1 -1
  88. package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-CQgzQ6jn.js → xychartDiagram-ELKLHX3M-CfBcgJ_K.js} +1 -1
  89. package/dist/worker/console/static/index.html +2 -2
  90. package/dist/worker/console/static-src/app/console-types.js +0 -12
  91. package/dist/worker/console/static-src/app/useOperatorActions.js +1 -1
  92. package/dist/worker/console/static-src/app/useRecoveryActions.js +2 -2
  93. package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +38 -1
  94. package/dist/worker/console/static-src/operator-chat/open-preview-in-browser.js +328 -0
  95. package/dist/worker/console/static-src/operator-chat/turn-stream-controller.js +8 -1
  96. package/dist/worker/console/static-src/operator-chat/turn-submission.js +42 -0
  97. package/dist/worker/console/static-src/operator-chat/useChatSessions.js +3 -0
  98. package/dist/worker/console/static-src/operator-chat/useChatStream.js +204 -11
  99. package/dist/worker/console/static-src/operator-chat/useChatThread.js +23 -1
  100. package/dist/workflows/dag/backend-test-case-coverage-analysis.js +809 -53
  101. package/dist/workflows/dag/backend-test-case-manifest.js +4 -0
  102. package/dist/workflows/dag/backend-test-execution-contract.js +18 -9
  103. package/dist/workflows/dag/backend-test-gap-fill.js +205 -0
  104. package/dist/workflows/dag/backend-test-intake-context.js +32 -0
  105. package/dist/workflows/dag/backend-test-layout.js +133 -0
  106. package/dist/workflows/dag/backend-test-markdown-workflow.js +167 -32
  107. package/dist/workflows/dag/backend-test-module-stem.js +5 -0
  108. package/dist/workflows/dag/backend-test-pytest-collection.js +368 -33
  109. package/dist/workflows/dag/backend-test-result-contract.js +1 -1
  110. package/dist/workflows/dag/backend-test-scenario-param.js +884 -140
  111. package/dist/workflows/dag/backend-test-scenario-partitions.js +321 -0
  112. package/dist/workflows/dag/backend-test-writer-completeness.js +100 -56
  113. package/dist/workflows/dag/contract-validator-registrations.js +2 -1
  114. package/dist/workflows/dag/convergence/controller.js +141 -0
  115. package/dist/workflows/dag/dynamic-runtime/map.js +24 -8
  116. package/dist/workflows/dag/dynamic-runtime/shared.js +1 -1
  117. package/dist/workflows/dag/frontend-implementation-contract.js +319 -13
  118. package/dist/workflows/dag/frontend-prewrite-gate.js +200 -45
  119. package/dist/workflows/dag/init-hybrid.js +689 -91
  120. package/dist/workflows/dag/node-execution.js +71 -18
  121. package/dist/workflows/dag/prompt.js +68 -1
  122. package/dist/workflows/dag/rerun-feedback.js +212 -0
  123. package/dist/workflows/dag/rerun-plan.js +93 -27
  124. package/dist/workflows/dag/rerun-run.js +3 -0
  125. package/dist/workflows/dag/rerun-task.js +61 -2
  126. package/dist/workflows/dag/retry-policy.js +18 -0
  127. package/dist/workflows/dag/types.js +104 -0
  128. package/dist/workflows/dag/upstream-artifacts.js +4 -0
  129. package/docs/operations/local-development-environment.md +1 -5
  130. package/docs/skills/vetted-skill-registry.md +14 -0
  131. package/docs/templates/README.md +1 -1
  132. package/docs/templates/backend-test-dag.json +60 -35
  133. package/docs/templates/harness.schema.json +0 -8
  134. package/harness.json +1 -8
  135. package/package.json +8 -4
  136. package/skills/analyze-product-requirements/SKILL.md +8 -5
  137. package/skills/analyze-product-requirements/references/acceptance-criteria.md +1 -1
  138. package/skills/analyze-product-requirements/references/clarification-and-knowledge.md +10 -6
  139. package/skills/analyze-product-requirements/references/example.md +50 -0
  140. package/skills/analyze-product-requirements/references/forward-test-cases.md +11 -7
  141. package/skills/analyze-product-requirements/references/kb-integration.md +5 -5
  142. package/skills/analyze-product-requirements/references/product-analysis-schema.md +8 -4
  143. package/skills/analyze-product-requirements/references/product-requirement-schema.md +2 -2
  144. package/skills/analyze-product-requirements/references/requirement-clarification-schema.md +1 -1
  145. package/skills/analyze-product-requirements/scripts/test-validators.mjs +11 -1
  146. package/skills/analyze-product-requirements/scripts/validate-product-analysis.mjs +20 -1
  147. package/skills/analyze-product-requirements/scripts/validate-requirement-clarification.mjs +9 -0
  148. package/skills/frontend-implementation/references/node-contracts.md +2 -2
  149. package/skills/improve-codebase-architecture/SKILL.md +81 -0
  150. package/skills/improve-codebase-architecture/deepening.md +37 -0
  151. package/skills/improve-codebase-architecture/html-report.md +123 -0
  152. package/skills/improve-codebase-architecture/interface-design.md +44 -0
  153. package/skills/improve-codebase-architecture/language.md +53 -0
  154. package/dist/worker/console/static/assets/channel-Dp_2Aqf1.js +0 -1
  155. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL--CODy37j.js +0 -1
  156. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE--CODy37j.js +0 -1
  157. package/dist/worker/console/static/assets/index-BA5-N5ER.css +0 -1
  158. package/dist/worker/console/static/assets/index-DKPXBrdc.js +0 -325
  159. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-B-mvnLEc.js +0 -1
  160. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-JtpBmIv4.js +0 -8
@@ -3,7 +3,8 @@ import path from "node:path";
3
3
  import { generateTaskDagUseCase } from "../../application/dag/generate-task-dag.js";
4
4
  import { writeJsonAtomic } from "../../infrastructure/harness/atomic-write.js";
5
5
  import { DAG_RUNS_DIR, isTerminalDagRunStatus, locateDagRun, readDagRunSpec, readDagRunState, } from "./lifecycle.js";
6
- import { parseDagSpec } from "./types.js";
6
+ import { deriveDagRerunFeedback } from "./rerun-feedback.js";
7
+ import { parseDagSpec, } from "./types.js";
7
8
  export const RERUN_TASK_LINEAGE_REL_PATH = ".runtime/rerun-task-lineage.json";
8
9
  export function parseDagRerunTaskArgs(args) {
9
10
  if (args.length === 0) {
@@ -218,6 +219,7 @@ async function writeRerunTaskLineage(cwd, newRunId, input) {
218
219
  parentRunId: input.parentRunId,
219
220
  reason: input.reason,
220
221
  requestId: input.requestId,
222
+ feedback: input.feedback,
221
223
  createdAt: new Date().toISOString(),
222
224
  }, { repoRoot: cwd, allowCompletedFactsWrite: true });
223
225
  }
@@ -228,12 +230,30 @@ function blockedResult(input) {
228
230
  reason: input.reason,
229
231
  requestId: input.requestId,
230
232
  mode: "blocked",
233
+ feedback: input.feedback ?? {
234
+ inherited: false,
235
+ reason: "no-unresolved-verify-review-feedback",
236
+ },
231
237
  blockedReason: input.blockedReason,
232
238
  ...(input.note ? { note: input.note } : {}),
233
239
  ...(input.taskId ? { taskId: input.taskId } : {}),
234
240
  ...(input.conflictPaths ? { conflictPaths: input.conflictPaths } : {}),
235
241
  };
236
242
  }
243
+ async function readGeneratedRerunFeedback(outputPath) {
244
+ const raw = JSON.parse(await readFile(outputPath, "utf8"));
245
+ return parseDagSpec(raw).rerunFeedback;
246
+ }
247
+ function summarizeFeedback(feedback, fallbackReason) {
248
+ return feedback
249
+ ? {
250
+ inherited: true,
251
+ sourceNodeId: feedback.sourceNodeId,
252
+ digest: feedback.digest,
253
+ bindingStatus: feedback.binding.status,
254
+ }
255
+ : { inherited: false, reason: fallbackReason };
256
+ }
237
257
  function extractRunSummary(generateResult) {
238
258
  if (generateResult.mode === "generate+basic-validate")
239
259
  return undefined;
@@ -277,7 +297,26 @@ export async function rerunStandaloneTask(input) {
277
297
  note: eligibility.note,
278
298
  });
279
299
  }
300
+ let parentFeedback;
301
+ let missingFeedbackReason = "no-unresolved-verify-review-feedback";
302
+ try {
303
+ parentFeedback = await deriveDagRerunFeedback({
304
+ parentRunId: input.parentRunId,
305
+ taskId: taskResolution.taskId,
306
+ runDir: located.runDir,
307
+ spec,
308
+ state,
309
+ });
310
+ }
311
+ catch {
312
+ // Feedback is additive recovery context. A corrupt/missing historical
313
+ // artifact must be reported honestly but must not block an otherwise
314
+ // eligible full rerun.
315
+ missingFeedbackReason = "feedback-unavailable";
316
+ }
280
317
  const execute = input.execute ?? true;
318
+ let effectiveFeedback;
319
+ let expectedRerunFeedbackDigest;
281
320
  // AC-001 generated-output-conflict preflight: when a real execution is
282
321
  // requested, first generate the DAG draft (execute:false) so we can inspect
283
322
  // the regenerated spec's requireChangedFiles writer write sets against
@@ -296,15 +335,23 @@ export async function rerunStandaloneTask(input) {
296
335
  dryRun: false,
297
336
  profile: input.profile ?? "auto",
298
337
  profileExplicit: input.profileExplicit ?? false,
338
+ rerunFeedback: parentFeedback,
299
339
  });
300
340
  if (preflight.mode === "generate+basic-validate") {
301
341
  let conflictPaths = [];
302
342
  try {
303
343
  const raw = await readFile(preflight.outputPath, "utf8");
304
344
  const preflightSpec = parseDagSpec(JSON.parse(raw));
345
+ effectiveFeedback = preflightSpec.rerunFeedback;
346
+ expectedRerunFeedbackDigest = effectiveFeedback?.digest;
347
+ if (parentFeedback && !effectiveFeedback) {
348
+ throw new Error("rerun feedback missing from generated preflight DAG");
349
+ }
305
350
  conflictPaths = await assessGeneratedOutputConflict(preflightSpec, input.cwd);
306
351
  }
307
- catch {
352
+ catch (error) {
353
+ if (parentFeedback)
354
+ throw error;
308
355
  // If the draft cannot be parsed, fall through to the real execution
309
356
  // path: execution's own validation will surface the structural defect.
310
357
  conflictPaths = [];
@@ -332,7 +379,17 @@ export async function rerunStandaloneTask(input) {
332
379
  dryRun: false,
333
380
  profile: input.profile ?? "auto",
334
381
  profileExplicit: input.profileExplicit ?? false,
382
+ rerunFeedback: parentFeedback,
383
+ expectedRerunFeedbackDigest,
335
384
  });
385
+ if (parentFeedback && !effectiveFeedback) {
386
+ effectiveFeedback = await readGeneratedRerunFeedback(generateResult.outputPath);
387
+ }
388
+ if (expectedRerunFeedbackDigest &&
389
+ effectiveFeedback?.digest !== expectedRerunFeedbackDigest) {
390
+ throw new Error(`rerun feedback drift after generation: expected ${expectedRerunFeedbackDigest}, got ${effectiveFeedback?.digest ?? "missing"}`);
391
+ }
392
+ const feedbackSummary = summarizeFeedback(effectiveFeedback, missingFeedbackReason);
336
393
  const newRunId = extractNewRunId(generateResult);
337
394
  const runSummary = extractRunSummary(generateResult);
338
395
  const completedSuccessfully = !execute ||
@@ -342,6 +399,7 @@ export async function rerunStandaloneTask(input) {
342
399
  parentRunId: input.parentRunId,
343
400
  reason: input.reason,
344
401
  requestId: input.requestId,
402
+ feedback: feedbackSummary,
345
403
  });
346
404
  }
347
405
  const result = {
@@ -350,6 +408,7 @@ export async function rerunStandaloneTask(input) {
350
408
  reason: input.reason,
351
409
  requestId: input.requestId,
352
410
  mode: "generate+validate+execute",
411
+ feedback: feedbackSummary,
353
412
  taskId: taskResolution.taskId,
354
413
  ...(newRunId ? { newRunId } : {}),
355
414
  ...(runSummary && !completedSuccessfully && "status" in runSummary
@@ -201,6 +201,24 @@ function isExclusivePiImplementer(task) {
201
201
  !task.dynamicCondition &&
202
202
  !task.dynamicLoopUntil);
203
203
  }
204
+ /**
205
+ * Provider/transport failure categories that can crash a writer executor
206
+ * after some workspace writes already landed on disk. A continuation may
207
+ * restart that writer itself; it must never import or normalize the ERROR fact.
208
+ */
209
+ export const WRITER_TRANSPORT_FAILURE_CATEGORIES = new Set([
210
+ "unavailable",
211
+ "network",
212
+ "rate-limit",
213
+ "timeout",
214
+ ]);
215
+ export function isTransportCrashedExclusiveWriter(task, failureCategory) {
216
+ if (!task)
217
+ return false;
218
+ return (isExclusivePiImplementer(task) &&
219
+ failureCategory !== undefined &&
220
+ WRITER_TRANSPORT_FAILURE_CATEGORIES.has(failureCategory));
221
+ }
204
222
  /**
205
223
  * Static eligibility for the requireChangedFiles writer-empty-diff class.
206
224
  * The Pi executor assigns writer-empty-diff only after post-write-guard
@@ -423,6 +423,8 @@ export const dagBackendTestPipelineSchema = z.enum([
423
423
  "markdown-scenario-param",
424
424
  "markdown-execute-html",
425
425
  "markdown-manifest",
426
+ "markdown-report",
427
+ "ingest-backend-test-gap",
426
428
  ]);
427
429
  export const dagFrontendBrowserToolPreflightSchema = z.object({}).strict();
428
430
  export const dagFrontendTestEvidenceValidationSchema = z.object({}).strict();
@@ -600,6 +602,13 @@ export const dagDynamicExpansionSchema = z.object({
600
602
  maxTotalTokens: z.number().int().positive().optional(),
601
603
  })
602
604
  .optional(),
605
+ /**
606
+ * When true, any child blocked by the aggregate token budget fails the map
607
+ * barrier instead of being retained as a case-level blocked outcome.
608
+ * Backend-test enables this because partial Markdown/pytest module sets are
609
+ * invalid generation assets; frontend-test keeps the default false.
610
+ */
611
+ failOnTokenBudgetExhaustion: z.boolean().optional(),
603
612
  /**
604
613
  * When true, map child ERROR/auth/timeout is recorded as case-level
605
614
  * failed/blocked evidence and the map barrier still succeeds (frontend-test).
@@ -704,6 +713,7 @@ export const dagConvergenceSpecSchema = z
704
713
  */
705
714
  export const structuredContractOutputSchemaIds = [
706
715
  "frontend-implementation-contract-v1",
716
+ "frontend-implementation-contract-plan-patch-v1",
707
717
  "frontend-implementation-contract-revision-patch-v1",
708
718
  ];
709
719
  export const dagTaskSchema = z.object({ id: z.string().regex(/^[a-z][a-z0-9-]*$/, "task id must be kebab-case"),
@@ -766,9 +776,32 @@ export const dagTaskSchema = z.object({ id: z.string().regex(/^[a-z][a-z0-9-]*$/
766
776
  .object({
767
777
  schemaId: z.enum(structuredContractOutputSchemaIds),
768
778
  retryOnInvalid: z.boolean().default(true),
779
+ /**
780
+ * Optional deterministic base object for patch-producing structured
781
+ * nodes. The frontend plan patch validator applies the model delta to
782
+ * this run-owned skeleton before strict contract validation.
783
+ */
784
+ skeleton: z.record(z.string(), z.unknown()).optional(),
769
785
  })
770
786
  .strict()
787
+ .superRefine((value, ctx) => {
788
+ if (value.schemaId ===
789
+ "frontend-implementation-contract-plan-patch-v1" &&
790
+ !value.skeleton) {
791
+ ctx.addIssue({
792
+ code: "custom",
793
+ message: "frontend plan patch output requires a runtime skeleton",
794
+ path: ["skeleton"],
795
+ });
796
+ }
797
+ })
771
798
  .optional(),
799
+ /**
800
+ * Opt-in upstream context mode for nodes that must consume a validated,
801
+ * hash-bound artifact rather than a potentially truncated text preview.
802
+ * The default remains preview mode for every existing DAG.
803
+ */
804
+ artifactFirstUpstreamNodeIds: z.array(z.string()).optional(),
772
805
  /**
773
806
  * Fail-closed outcome/diff consistency contract for bounded Pi writers.
774
807
  * The writer must begin with IMPLEMENTATION_OUTCOME: changed,
@@ -846,6 +879,55 @@ export const dagSourceBindingSchema = z.object({
846
879
  .min(1),
847
880
  requirementIds: z.array(z.string().regex(/^(?:REQ|BR|AC)-[A-Z0-9]+(?:-[A-Z0-9]+)*$/)),
848
881
  });
882
+ const dagRerunFeedbackEvidencePathSchema = z
883
+ .string()
884
+ .min(1)
885
+ .refine((value) => !/^(?:[A-Za-z]:[\\/]|[\\/]{2}|\/)/.test(value), "rerun feedback evidence paths must be repository-relative");
886
+ /**
887
+ * Bounded unresolved verify/review feedback carried by a full task rerun.
888
+ * This is recovery context, not a mutation of the original task contract.
889
+ */
890
+ export const dagRerunFeedbackSchema = z
891
+ .object({
892
+ schemaVersion: z.literal(1),
893
+ kind: z.literal("unresolved-terminal-feedback"),
894
+ parentRunId: z.string().min(1),
895
+ taskId: z.string().min(1),
896
+ sourceNodeId: z.string().min(1),
897
+ verdict: z.enum(["request-revision", "fail"]).optional(),
898
+ failureCategory: z.string().min(1).optional(),
899
+ feedbackText: z.string().min(1).max(12_000),
900
+ evidenceRefs: z
901
+ .array(z
902
+ .object({
903
+ nodeId: z.string().min(1),
904
+ preservedNodeRecordPath: dagRerunFeedbackEvidencePathSchema,
905
+ })
906
+ .strict())
907
+ .max(8),
908
+ attemptSummary: z
909
+ .object({
910
+ completedPasses: z.number().int().positive(),
911
+ maxPasses: z.number().int().positive(),
912
+ terminalReason: z.string().min(1).optional(),
913
+ })
914
+ .strict(),
915
+ binding: z
916
+ .object({
917
+ sourceCanonicalHash: z
918
+ .string()
919
+ .regex(/^[a-f0-9]{64}$/)
920
+ .optional(),
921
+ taskContractCanonicalHash: z
922
+ .string()
923
+ .regex(/^[a-f0-9]{64}$/)
924
+ .optional(),
925
+ status: z.enum(["exact", "changed", "unknown"]),
926
+ })
927
+ .strict(),
928
+ digest: z.string().regex(/^[a-f0-9]{64}$/),
929
+ })
930
+ .strict();
849
931
  export const dagSpecSchema = z
850
932
  .object({
851
933
  version: dagVersionSchema,
@@ -857,6 +939,28 @@ export const dagSpecSchema = z
857
939
  sourceBinding: dagSourceBindingSchema.optional(),
858
940
  /** v4 managed Task Contract binding; only valid on version 4. */
859
941
  taskContractBinding: dagTaskContractBindingSchema.optional(),
942
+ /** Optional unresolved parent-run feedback for a full task rerun. */
943
+ rerunFeedback: dagRerunFeedbackSchema.optional(),
944
+ /** Frozen backend-test artifact layout (plan A); absent = historical default testcase/ layout. */
945
+ backendTestLayout: z
946
+ .object({
947
+ testRoot: z.string(),
948
+ markdownRel: z.string(),
949
+ scriptRel: z.string(),
950
+ markdownDir: z.string(),
951
+ scriptDir: z.string(),
952
+ readmePath: z.string(),
953
+ isDefault: z.boolean(),
954
+ })
955
+ .optional(),
956
+ /** Bound user shared-setup document (plan B); absent = no shared setup references expected. */
957
+ backendTestSharedSetup: z
958
+ .object({
959
+ path: z.string(),
960
+ readPath: z.string(),
961
+ sha256: z.string(),
962
+ })
963
+ .optional(),
860
964
  outputLanguage: dagOutputLanguageSchema.optional(),
861
965
  objective: z.string().optional(),
862
966
  successCriteria: z.array(z.string()).optional(),
@@ -38,6 +38,10 @@ export function relocateNodeArtifactPaths(node, oldRunDir, newRunDir) {
38
38
  node.stdoutArtifactPath = rewrite(node.stdoutArtifactPath);
39
39
  node.assistantArtifactPath = rewrite(node.assistantArtifactPath);
40
40
  node.structuredArtifactPath = rewrite(node.structuredArtifactPath);
41
+ if (node.frontendPlanOutput) {
42
+ node.frontendPlanOutput.citationsArtifactPath = rewrite(node.frontendPlanOutput.citationsArtifactPath);
43
+ node.frontendPlanOutput.rawCandidatePath = rewrite(node.frontendPlanOutput.rawCandidatePath);
44
+ }
41
45
  node.nodeRecordPath = rewrite(node.nodeRecordPath);
42
46
  }
43
47
  export function relocateConvergenceArtifactPaths(convergence, oldRunDir, newRunDir) {
@@ -29,11 +29,7 @@ Cursor Cloud VM 当前有两个需要特别注意的环境问题。
29
29
 
30
30
  ### Node.js 版本
31
31
 
32
- VM 默认 `node`(`/exec-daemon/node`)可能是 v22.14.0,但可选依赖 `@earendil-works/pi-ai` / `@earendil-works/pi-coding-agent` 要求 Node.js `>=22.19.0`。版本过低时,`npm install` / `npm ci` 可能跳过这些依赖,随后 `npm run typecheck``npm run build` 会报告:
33
-
34
- ```text
35
- Cannot find module '@earendil-works/...'
36
- ```
32
+ VM 默认 `node`(`/exec-daemon/node`)可能是 v22.14.0,但根包与运行时依赖 `@earendil-works/pi-ai` / `@earendil-works/pi-coding-agent` 都要求 Node.js `>=22.19.0`。版本过低时,npm 默认模式会报告 `EBADENGINE` 警告;启用 `engine-strict` 时,`npm install` / `npm ci` 会直接失败。即使默认模式完成安装,也不应在不受支持的 Node.js 版本上继续执行 typecheck、buildruntime 命令。
37
33
 
38
34
  在 Cursor Cloud 中执行安装或验证前,先切换到已配置的 Node.js 22:
39
35
 
@@ -16,10 +16,22 @@ The entries below are local wrappers or existing local skills. They are not whol
16
16
  | `code-review-core` | local wrapper inspired by code review practice | `skills/code-review-core/SKILL.md` | reviewer | reviewer | No external tools or network by default. |
17
17
  | `codebase-scout` | local wrapper | `skills/codebase-scout/SKILL.md` | scout | scout | Read-only reconnaissance guidance. |
18
18
  | `init-capability-evolution` | local wrapper | `skills/init-capability-evolution/SKILL.md` | supervisor, maintenance | optional | Used only when changes may affect target-project initialization, package surface, or init projection rules. |
19
+ | `frontend-implementation` | local existing (frontend hybrid DAG) | `skills/frontend-implementation/SKILL.md` | frontend plan / contract / scout / mock nodes (spec-level `skillsByRole`) | frontend-implementation DAG only | Required refs node-contracts / design-spec / code-standards; injected by `init-hybrid.ts` spec generation and `src/adapters/loop-agent.ts`; projected via init-surface manifest. Not in `DEFAULT_SKILLS_BY_ROLE`. |
20
+ | `frontend-review` | local existing (frontend hybrid DAG) | `skills/frontend-review/SKILL.md` | reviewer (frontend review nodes, spec-level) | frontend-implementation / repair DAGs | Consumed by `init-hybrid.ts` / `frontend-repair.ts` / `shell-executor.ts`; required ref review-findings (maxChars 2800). |
21
+ | `frontend-verification` | local existing (frontend hybrid DAG) | `skills/frontend-verification/SKILL.md` | verifier / closeout (frontend evidence, spec-level) | frontend DAG closeout | Consumed by `shell-executor.ts` / `frontend-repair.ts` / `frontend-review-context.ts`; required ref verification-checklist. |
22
+ | `frontend-design-review` | local existing (frontend hybrid DAG) | `skills/frontend-design-review/SKILL.md` | design-gate reviewer (before any writer) | frontend-implementation DAG design gate | Injected by `init-hybrid.ts`; runs before the prewrite gate authorizes writers; required ref review-checklist. |
23
+ | `frontend-bounded-implement` | local existing (frontend hybrid DAG) | `skills/frontend-bounded-implement/SKILL.md` | implementer (writer nodes, spec-level) | frontend writers after canonical contract gate | Injected by `init-hybrid.ts`; writers run only after the canonical contract gate accepts and only inside the frozen writeSet (ADR 0015/0016 discipline). |
19
24
  | `grill-with-docs` | local operator skill adapted from domain grilling + ADR/glossary discipline | `skills/grill-with-docs/SKILL.md` | explicit interactive operator only | never a default DAG role | Resolves decisions via `harness.json.governanceRoot`; required refs `context-format.md` / `adr-format.md`; respects writeSet; not in `DEFAULT_SKILLS_BY_ROLE`. |
25
+ | `grill-me` | local interview question engine wrapper | `skills/grill-me/SKILL.md` | interview runtime dependency (not a DAG role) | never a default DAG role | Question engine lives in `src/worker/console/interview/grill-me.ts` (Console interview / operator-actions); intentionally NOT projected by init-surface manifest — runs in this repo's Console only. |
26
+ | `analyze-product-requirements` | local org-internal Product Analysis V4 skill | `skills/analyze-product-requirements/SKILL.md` | source-prepare dependency (not a DAG role) | never a default DAG role | Loaded by `src/task/source-prepare/prepare.ts` during 任务源 preparation; IRON-LAW freeze semantics on `product-analysis.md`; intentionally NOT projected by init-surface manifest. |
20
27
  | `webapp-testing` | local wrapper inspired by frontend/browser testing practice | `skills/webapp-testing/SKILL.md` | verifier, reviewer | optional | Only applies when task explicitly involves browser-rendered behavior; no default Playwright/Semgrep execution. |
21
28
  | `playwright-cli` | repo-local Playwright CLI instructions | `skills/playwright-cli/SKILL.md` | FE-test case executor | FE-test only | Direct browser commands require isolated test environments, per-case evidence paths, and explicit credential/data handling. |
22
29
  | `playwright-cli-case-generator` | adapted from the repo-local playwright CLI case-generator contract | `skills/playwright-cli-case-generator/SKILL.md` | FE-test case generator | FE-test only | Generates Markdown cases and a compact manifest from RAG facts; does not execute browsers, create test code, or invent API/data constraints. |
30
+ | `analyze-product-dependencies` | local org-internal product dependency analysis | `skills/analyze-product-dependencies/SKILL.md` | explicit interactive operator only | never a default DAG role | PRD → code/API mapping analysis; read-only; no runtime references; not projected. |
31
+ | `browser-tools` | local operator skill (CDP automation) | `skills/browser-tools/SKILL.md` | explicit interactive operator only | never a default DAG role | Requires user-visible Chrome with remote debugging (:9222); credential/data handling reviewed per use; not projected. |
32
+ | `local-jacoco-coverage` | local operator orchestration skill | `skills/local-jacoco-coverage/SKILL.md` | explicit interactive operator only | never a default DAG role | Orchestrates backend-test DAGs with a JaCoCo agent — it drives DAGs, so it must never be loaded by one (no recursion); not projected. |
33
+ | `using-git-worktrees` | local wrapper | `skills/using-git-worktrees/SKILL.md` | explicit interactive operator only | never a default DAG role | Workspace isolation guidance only; no runtime references; not projected. |
34
+ | `improve-codebase-architecture` | local operator skill (copied from shared agent platform 2026-08-21) | `skills/improve-codebase-architecture/SKILL.md` | explicit interactive operator only | never a default DAG role | Interactive architecture review producing a temp HTML report; reads CONTEXT.md glossary + `docs/decisions/` ADRs; cross-directory refs `../grill-with-docs/{context,adr}-format.md` are exempt (see Vetting Rules); not projected. |
23
35
 
24
36
  ## Verification placement taxonomy
25
37
 
@@ -42,6 +54,8 @@ Authoring vocabulary for where a check or verification skill should live. Prefer
42
54
  - Default role mappings may reference only repo-local skills that resolve cleanly under `dag validate --strict-skills`.
43
55
  - `agent-worker` is explicitly outside default role mappings. Its trigger description must cover `agent-worker`, Feature Packet, TaskSpec, Task Pool, self-host/candidate and the `loop-agent` routing boundary; `scripts/check-skill-entry.sh` enforces this public entry contract.
44
56
  - `grill-with-docs` is an explicit interactive operator skill only; it must stay outside `DEFAULT_SKILLS_BY_ROLE`.
57
+ - Registry ↔ disk sync: every `skills/*/SKILL.md` in the repo must have a row above. Operator-local skills are recorded with `never a default DAG role` instead of being omitted, so an audit cannot mistake them for drift.
58
+ - `improve-codebase-architecture` is exempt from the "references stay within the skill directory" rule: it is operator-only, never resolved by DAG skill snapshots, and reuses `grill-with-docs` context/ADR formats by relative path.
45
59
  - Optional/security/web skills remain task- or profile-specific until their tool, network, credential, and write behavior is reviewed.
46
60
  - This registry records source inspiration, not license clearance for vendored third-party content. Vendoring requires a separate license/security review.
47
61
  - `SKILL.md` is the entry point. References must be declared in frontmatter and stay within the skill directory.
@@ -30,7 +30,7 @@
30
30
 
31
31
  ## Backend-test
32
32
 
33
- - `backend-test-dag.json` — backend-test DAG 模板;其中 `generate-backend-md-cases-pi` 是唯一允许 `writer-empty-diff` 重试的 writer(总共两次,仅限 post-write-guard attribution 确认的空 diff)。
33
+ - `backend-test-dag.json` — backend-test DAG 模板;其中 `generate-backend-md-cases-pi` 是唯一允许 `writer-empty-diff` 重试的 writer(总共两次,仅限 post-write-guard attribution 确认的空 diff);N2/N5 合同限定 Scenario Partition 必须有源有限域。
34
34
  - `backend-test-dag.classify.prompt.md`、`backend-test-dag.generate-pytest.prompt.md`、`backend-test-dag.review-cases.prompt.md`、`backend-test-dag.retrospect.prompt.md` — 分类、生成、审查和复盘提示。
35
35
  - `backend-test-analysis.schema.json`、`backend-test-execution.schema.json`、`backend-test-result.schema.json`、`backend-test-case-manifest.schema.json` — 分析、执行、结果与用例清单 schema。
36
36