@tea-agent/loop-agent 0.33.6 → 0.33.7-beta.1

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 (69) hide show
  1. package/CHANGELOG.md +39 -23
  2. package/dist/application/task-lifecycle/advance.js +4 -254
  3. package/dist/application/task-lifecycle/gates.js +0 -50
  4. package/dist/application/task-lifecycle/observe.js +2 -11
  5. package/dist/commands/init-upgrade.js +1 -32
  6. package/dist/commands/init.js +3 -94
  7. package/dist/executors/shell-executor.js +91 -4
  8. package/dist/executors/shell-write-guard.js +8 -26
  9. package/dist/shared/operator/capabilities.js +42 -72
  10. package/dist/task/source-prepare/index.js +0 -2
  11. package/dist/task/source-prepare/parse-intent.js +10 -58
  12. package/dist/task/source-prepare/prepare.js +16 -180
  13. package/dist/task/source-prepare/reference-integrity.js +2 -18
  14. package/dist/worker/console/app-data.js +0 -2
  15. package/dist/worker/console/chat/chat-event-store.js +25 -190
  16. package/dist/worker/console/chat/instruction-skills.js +217 -0
  17. package/dist/worker/console/chat/pi-console-config.js +32 -250
  18. package/dist/worker/console/chat/pi-runtime.js +71 -625
  19. package/dist/worker/console/chat/resource-loader.js +4 -5
  20. package/dist/worker/console/chat/routes.js +146 -324
  21. package/dist/worker/console/chat/runtime-context.js +12 -48
  22. package/dist/worker/console/chat/runtime-selection.js +0 -59
  23. package/dist/worker/console/chat/shortcuts.js +0 -1
  24. package/dist/worker/console/chat/tool-adapter.js +3 -9
  25. package/dist/worker/console/chat/tools.js +1 -5
  26. package/dist/worker/console/operator-actions.js +68 -559
  27. package/dist/worker/console/server.js +15 -8
  28. package/dist/worker/console/static/assets/index-CnUXAqxG.css +1 -0
  29. package/dist/worker/console/static/assets/index-CteJFFL2.js +29 -0
  30. package/dist/worker/console/static/index.html +2 -2
  31. package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +8 -45
  32. package/dist/worker/console/static-src/operator-chat/refs.js +0 -9
  33. package/dist/worker/console/static-src/operator-chat/useChatSessions.js +0 -16
  34. package/dist/worker/console/static-src/operator-chat/useChatStream.js +184 -210
  35. package/dist/worker/console/static-src/operator-chat/useChatThread.js +5 -49
  36. package/dist/worker/console/static-src/operator-chat/useComposer.js +0 -17
  37. package/dist/worker/console/static-src/operator-chat/useRuntimeControls.js +74 -225
  38. package/dist/worker/delivery/final-verification.js +5 -13
  39. package/dist/worker/delivery/package.js +19 -31
  40. package/dist/worker/delivery/verification-bundle.js +4 -6
  41. package/dist/worker/observe/static/operator-chrome.css +2 -5
  42. package/dist/worker/observe/static/operator-chrome.js +1 -6
  43. package/dist/worker/observe/static/styles.css +9 -39
  44. package/dist/workflows/dag/backend-test-case-coverage-analysis.js +462 -33
  45. package/dist/workflows/dag/backend-test-case-manifest.js +4 -0
  46. package/dist/workflows/dag/backend-test-markdown-workflow.js +25 -1
  47. package/dist/workflows/dag/backend-test-module-stem.js +5 -0
  48. package/dist/workflows/dag/backend-test-pytest-collection.js +345 -24
  49. package/dist/workflows/dag/backend-test-scenario-param.js +552 -124
  50. package/dist/workflows/dag/backend-test-writer-completeness.js +47 -16
  51. package/dist/workflows/dag/dynamic-runtime/map.js +24 -8
  52. package/dist/workflows/dag/frontend-worktree-diff.js +27 -12
  53. package/dist/workflows/dag/init-hybrid.js +49 -37
  54. package/dist/workflows/dag/types.js +7 -0
  55. package/dist/workflows/dag/workspace-checkpoint.js +27 -8
  56. package/docs/templates/backend-test-dag.json +33 -30
  57. package/harness.json +1 -1
  58. package/package.json +1 -1
  59. package/skills/loop-agent/references/command-reference.md +1 -3
  60. package/skills/loop-agent/references/source-and-plan-practice.md +0 -13
  61. package/skills/loop-agent/references/task-workflow.md +0 -4
  62. package/dist/shared/resilient-git.js +0 -133
  63. package/dist/task/source-prepare/artifact-meta.js +0 -137
  64. package/dist/task/source-prepare/semantic-intake.js +0 -404
  65. package/dist/worker/console/dag-execution-receipt.js +0 -380
  66. package/dist/worker/console/static/assets/index-BUOLppPr.js +0 -28
  67. package/dist/worker/console/static/assets/index-C1KzazY5.css +0 -1
  68. package/dist/worker/console/static-src/operator-chat/runtime-snapshot-store.js +0 -257
  69. package/dist/worker/console/static-src/operator-chat/useRuntimeSnapshot.js +0 -196
@@ -1,19 +1,6 @@
1
1
  const HEADING_ALIASES = {
2
- objective: new Set([
3
- "目标",
4
- "objective",
5
- "问题与目标",
6
- "业务目标",
7
- "需求概述",
8
- ]),
9
- scope: new Set([
10
- "范围",
11
- "scope",
12
- "in scope",
13
- "需求范围",
14
- "已确认范围",
15
- "已确认需求",
16
- ]),
2
+ objective: new Set(["目标", "objective", "问题与目标"]),
3
+ scope: new Set(["范围", "scope", "in scope"]),
17
4
  nonGoals: new Set(["非目标", "out of scope", "non-goals", "non goals"]),
18
5
  acceptance: new Set(["验收标准", "acceptance criteria", "acceptance"]),
19
6
  constraints: new Set(["约束", "constraints", "不变式", "invariants"]),
@@ -21,8 +8,6 @@ const HEADING_ALIASES = {
21
8
  assumptions: new Set(["假设", "assumptions"]),
22
9
  };
23
10
  const OBJECTIVE_MAX_CHARS = 1200;
24
- /** Product Requirement V3/V4 style embedded AC heading, e.g. AC-FE-001 / AC-BE-12 / AC-001. */
25
- const EMBEDDED_AC_HEADING = /^(AC(?:[-_](?:FE|BE|UI|API))?[-_]?\d+(?:[-_]\d+)?)\s*[::]?\s*(.*)$/iu;
26
11
  function stripFencedAndComments(text) {
27
12
  // Remove fenced code blocks and HTML comments so headings inside them are ignored.
28
13
  return text
@@ -33,28 +18,10 @@ function stripFencedAndComments(text) {
33
18
  function normalizeHeadingText(raw) {
34
19
  return raw
35
20
  .trim()
36
- // Strip leading section numbers: "2. 业务目标" / "3.1 已确认范围" / "3.2、非目标"
37
- .replace(/^(?:\d+(?:\.\d+)*[..、]?\s*)+/u, "")
38
21
  .toLowerCase()
39
22
  .replace(/[::]\s*$/u, "")
40
23
  .replace(/\s+/g, " ");
41
24
  }
42
- function normalizeAcceptanceId(raw) {
43
- return raw
44
- .trim()
45
- .toUpperCase()
46
- .replace(/_/g, "-")
47
- .replace(/^(AC)(FE|BE|UI|API)(?=-|\d)/u, "$1-$2");
48
- }
49
- function parseEmbeddedAcHeading(headingText) {
50
- const normalized = headingText.trim().replace(/^(?:\d+(?:\.\d+)*[..、]?\s*)+/u, "");
51
- const match = EMBEDDED_AC_HEADING.exec(normalized);
52
- if (!match)
53
- return null;
54
- const id = normalizeAcceptanceId(match[1]);
55
- const text = match[2]?.trim() || id;
56
- return { id, text };
57
- }
58
25
  function classifyHeading(text) {
59
26
  const normalized = normalizeHeadingText(text);
60
27
  for (const [key, aliases] of Object.entries(HEADING_ALIASES)) {
@@ -81,17 +48,14 @@ function parseAcceptanceLine(line, nextId) {
81
48
  const body = (checklist?.[1] ?? bullet?.[1] ?? line.trim()).trim();
82
49
  if (!body)
83
50
  return null;
84
- const embedded = parseEmbeddedAcHeading(body);
85
- if (embedded)
86
- return embedded;
87
51
  const withId = /^(AC[-_]?\d+)\s*[::]\s*(.+)$/iu.exec(body);
88
52
  if (withId) {
89
- return { id: normalizeAcceptanceId(withId[1]), text: withId[2].trim() };
53
+ return { id: withId[1].toUpperCase().replace("_", "-"), text: withId[2].trim() };
90
54
  }
91
55
  const bareAc = /^(AC[-_]?\d+)\s+(.+)$/iu.exec(body);
92
56
  if (bareAc) {
93
57
  return {
94
- id: normalizeAcceptanceId(bareAc[1]),
58
+ id: bareAc[1].toUpperCase().replace("_", "-"),
95
59
  text: bareAc[2].trim(),
96
60
  };
97
61
  }
@@ -150,27 +114,9 @@ export function extractRequirementFactsFromMarkdown(markdown, options) {
150
114
  const sections = [];
151
115
  let current = { key: "other", lines: [] };
152
116
  sections.push(current);
153
- let acCounter = options?.acCounterStart ?? 1;
154
- const nextId = () => {
155
- const id = `AC-${String(acCounter).padStart(3, "0")}`;
156
- acCounter += 1;
157
- return id;
158
- };
159
117
  for (const line of lines) {
160
118
  const heading = isAtxHeading(line);
161
119
  if (heading) {
162
- // Product Requirement V3/V4 embeds formal AC as headings (#### AC-FE-001 ...).
163
- // Capture the heading as a single AC; GWT body lists under it stay non-AC.
164
- const embeddedAc = parseEmbeddedAcHeading(heading.text);
165
- if (embeddedAc) {
166
- sections.push({
167
- key: "acceptance",
168
- lines: [`- ${embeddedAc.id}: ${embeddedAc.text}`],
169
- });
170
- current = { key: "other", lines: [] };
171
- sections.push(current);
172
- continue;
173
- }
174
120
  const key = classifyHeading(heading.text);
175
121
  current = { key, lines: [] };
176
122
  sections.push(current);
@@ -178,6 +124,12 @@ export function extractRequirementFactsFromMarkdown(markdown, options) {
178
124
  }
179
125
  current.lines.push(line);
180
126
  }
127
+ let acCounter = options?.acCounterStart ?? 1;
128
+ const nextId = () => {
129
+ const id = `AC-${String(acCounter).padStart(3, "0")}`;
130
+ acCounter += 1;
131
+ return id;
132
+ };
181
133
  let objective;
182
134
  const scope = [];
183
135
  const nonGoals = [];
@@ -6,7 +6,6 @@ import { getTaskContractPaths } from "../contract/paths.js";
6
6
  import { loadTaskConfig } from "../runtime.js";
7
7
  import { buildPrepareDraft } from "./build-draft.js";
8
8
  import { hasBlockingGaps, hasBlockingRisks, isFreshLegacyUnversioned, listPrepareGaps, } from "./completeness.js";
9
- import { detectProductArtifactMeta, isIntakeSoftGapCode, } from "./artifact-meta.js";
10
9
  import { extractRequirementFactsFromMarkdown, fillMissingRequirementFacts, mergeRequirementFacts, } from "./parse-intent.js";
11
10
  import { draftReferencesFromManifest, validateImportedPrdReferences, } from "./reference-integrity.js";
12
11
  import { readSourceManifest } from "../source-references.js";
@@ -132,139 +131,31 @@ function mutationOutcome(code) {
132
131
  }
133
132
  function buildNextSteps(input) {
134
133
  const next = [];
135
- const codes = new Set(input.gaps.map((g) => g.code));
136
134
  if (!input.hasImportedPrd) {
137
- next.push(`loop-agent task advance ${input.taskId} --prd <product-requirement.md> --allowed-path <glob> --json`);
135
+ next.push(`loop-agent import-prd ${input.taskId} --file <prd.md> --role requirement`);
138
136
  }
139
- if (codes.has("PRODUCT_ANALYSIS_NOT_EXECUTABLE")) {
140
- next.push("使用同目录 product-requirement.md 作为 --prd(role=requirement);product-analysis.md 仅作引用(--role analysis)");
141
- next.push("禁止改写原始 product-analysis / product-requirement 产物,禁止在原 PRD 目录生成兼容 Markdown 或 reviewed-draft.json");
137
+ if (input.gaps.some((g) => g.code === "EMPTY_ALLOWED_PATHS")) {
138
+ next.push(" --allowed-path <glob>");
142
139
  }
143
- if (codes.has("PRODUCT_CLARIFICATION_NOT_EXECUTABLE")) {
144
- next.push("requirement-clarification.md 是决策追溯,不是可执行 PRD;请导入 complete product-requirement.md");
145
- }
146
- if (codes.has("PRODUCT_REQUIREMENT_PENDING")) {
147
- next.push("先完成 analyze-product-requirements 澄清并将 product-requirement.md 标为 complete,再 task advance --prd");
148
- }
149
- if (codes.has("EMPTY_ALLOWED_PATHS")) {
150
- next.push("补 --allowed-path <glob>(工程边界必须显式给出)");
151
- }
152
- if (codes.has("EMPTY_ACCEPTANCE") || codes.has("EMPTY_OBJECTIVE")) {
153
- next.push("PRD 真缺验收标准/目标时:补完整 product-requirement(Given/When/Then 或 AC 标题),或显式 --from-text;不要自动生成 sidecar draft JSON");
154
- }
155
- if (codes.has("SEMANTIC_INTAKE_RECOMMENDED")) {
156
- next.push("文档语义完整但结构非标准:整理为 product-requirement 或标准「目标/范围/非目标/验收标准」Markdown;不要在原 PRD 目录生成兼容 md/json");
157
- }
158
- if (codes.has("SEMANTIC_INTAKE_FAILED") || codes.has("SEMANTIC_INTAKE_INVALID_OUTPUT")) {
159
- next.push("semantic intake 未能产出可接受 draft:补全 product-requirement 或标准验收标准后重试;禁止在原 PRD 目录生成 sidecar JSON");
140
+ if (input.gaps.some((g) => g.code === "EMPTY_ACCEPTANCE")) {
141
+ next.push(" --ac <id:text> 或完善 PRD 验收标准章节");
160
142
  }
161
143
  if (input.mode === "dry-run" && input.ok) {
162
- next.push(`loop-agent task advance ${input.taskId} --allowed-path <glob> --json`);
144
+ next.push(`loop-agent task source prepare ${input.taskId} --use-imported-prd ... --apply --json`);
163
145
  }
164
146
  if (input.ok && input.mode === "apply") {
165
147
  next.push(`loop-agent task status ${input.taskId} --json`);
166
148
  next.push(`loop-agent task advance ${input.taskId} --profile auto --json`);
167
149
  next.push("审查 DAG writeSet 后再 task advance --approve-gate ...");
168
150
  }
169
- if (codes.has("DIRTY_SOURCE") ||
170
- codes.has("MANAGED_PROJECTION_INCOMPLETE")) {
171
- next.push(`高级恢复(仅人工 reviewed draft):loop-agent task advance ${input.taskId} --from-draft <reviewed-draft.json> --json`);
172
- next.push("--from-draft 不是 EMPTY_ACCEPTANCE 的默认恢复路径;禁止在原 PRD 目录自动生成 draft JSON");
151
+ if (input.gaps.some((g) => g.code === "DIRTY_SOURCE" || g.code === "MANAGED_PROJECTION_INCOMPLETE")) {
152
+ next.push(`loop-agent task advance ${input.taskId} --from-draft <reviewed-draft.json> --json`);
173
153
  }
174
- if (codes.has("TRANSACTION_INCOMPLETE")) {
154
+ if (input.gaps.some((g) => g.code === "TRANSACTION_INCOMPLETE")) {
175
155
  next.push(`loop-agent task advance ${input.taskId} --json`);
176
156
  }
177
157
  return next;
178
158
  }
179
- function appendProductArtifactGaps(input) {
180
- if (!input.sourceIntegrity)
181
- return;
182
- const docs = input.sourceIntegrity.documents.filter((d) => d.content);
183
- if (docs.length === 0)
184
- return;
185
- let sawAnalysisOnly = false;
186
- let sawClarificationOnly = false;
187
- let sawPendingRequirement = false;
188
- let sawExecutableRequirement = false;
189
- let sawUnknownNarrative = false;
190
- for (const doc of docs) {
191
- const meta = detectProductArtifactMeta(doc.content);
192
- if (meta.artifactType === "product-analysis") {
193
- sawAnalysisOnly = true;
194
- continue;
195
- }
196
- if (meta.artifactType === "requirement-clarification") {
197
- sawClarificationOnly = true;
198
- continue;
199
- }
200
- if (meta.artifactType === "product-requirement") {
201
- if (meta.requirementStatus &&
202
- meta.requirementStatus.trim().toLowerCase() === "pending") {
203
- sawPendingRequirement = true;
204
- }
205
- else {
206
- sawExecutableRequirement = true;
207
- }
208
- continue;
209
- }
210
- if (doc.role === "requirement" &&
211
- meta.artifactType === "unknown" &&
212
- !input.hasAcceptance) {
213
- sawUnknownNarrative = true;
214
- }
215
- }
216
- const hasRequirementRole = input.sourceIntegrity.parseableDocuments.some((d) => d.role === "requirement" || d.role === "acceptance");
217
- if (!hasRequirementRole && sawAnalysisOnly) {
218
- input.gaps.push({
219
- code: "PRODUCT_ANALYSIS_NOT_EXECUTABLE",
220
- level: "blocking",
221
- field: "acceptanceCriteria",
222
- message: "imported document is product-analysis (no formal AC by design); use product-requirement.md as --prd requirement",
223
- });
224
- }
225
- if (!hasRequirementRole &&
226
- sawClarificationOnly &&
227
- !sawExecutableRequirement) {
228
- input.gaps.push({
229
- code: "PRODUCT_CLARIFICATION_NOT_EXECUTABLE",
230
- level: "blocking",
231
- field: "acceptanceCriteria",
232
- message: "imported document is requirement-clarification (decision log only); use complete product-requirement.md",
233
- });
234
- }
235
- if (sawPendingRequirement && !input.hasAcceptance) {
236
- input.gaps.push({
237
- code: "PRODUCT_REQUIREMENT_PENDING",
238
- level: "blocking",
239
- field: "acceptanceCriteria",
240
- message: "product-requirement is still pending clarification; complete analyze-product-requirements before task advance",
241
- });
242
- }
243
- if (sawUnknownNarrative &&
244
- !input.hasAcceptance &&
245
- !sawPendingRequirement &&
246
- !sawAnalysisOnly) {
247
- input.gaps.push({
248
- code: "SEMANTIC_INTAKE_RECOMMENDED",
249
- level: "warning",
250
- message: "requirement body lacks structured AC headings; use product-requirement or standard Markdown sections — do not auto-write sidecar drafts",
251
- });
252
- }
253
- const precise = new Set([
254
- "PRODUCT_ANALYSIS_NOT_EXECUTABLE",
255
- "PRODUCT_CLARIFICATION_NOT_EXECUTABLE",
256
- "PRODUCT_REQUIREMENT_PENDING",
257
- ]);
258
- if (input.gaps.some((g) => precise.has(g.code))) {
259
- for (const gap of input.gaps) {
260
- if (gap.code === "EMPTY_ACCEPTANCE") {
261
- gap.level = "warning";
262
- gap.message =
263
- "acceptance criteria empty (superseded by product-artifact diagnostic)";
264
- }
265
- }
266
- }
267
- }
268
159
  function emptyObservedHashPlaceholder() {
269
160
  return "0".repeat(64);
270
161
  }
@@ -498,36 +389,13 @@ export async function prepareTaskSource(input) {
498
389
  message: "no parseable requirement document and no --ac / supplemental text; import a requirement-role PRD or pass flags",
499
390
  });
500
391
  }
501
- // Product Analysis / pending Product Requirement diagnostics (precise gaps).
502
- if (input.intent.kind === "facts" && input.intent.useImportedPrd) {
503
- appendProductArtifactGaps({
504
- gaps,
505
- sourceIntegrity,
506
- hasAcceptance: built.draft.requirement.acceptanceCriteria.length > 0,
507
- });
508
- }
509
392
  const validation = await validateDraftForTask({
510
393
  repoRoot,
511
394
  taskId,
512
395
  draft: built.draft,
513
396
  });
514
397
  if (!validation.ok) {
515
- const productArtifactBlocking = gaps.some((gap) => [
516
- "PRODUCT_ANALYSIS_NOT_EXECUTABLE",
517
- "PRODUCT_CLARIFICATION_NOT_EXECUTABLE",
518
- "PRODUCT_REQUIREMENT_PENDING",
519
- ].includes(gap.code));
520
398
  for (const message of validation.errors) {
521
- const isAcceptanceSchema = /acceptance criterion|acceptanceCriteria/i.test(message);
522
- // Prefer product-artifact diagnostics over generic schema AC errors.
523
- if (productArtifactBlocking && isAcceptanceSchema) {
524
- gaps.push({
525
- code: "DRAFT_VALIDATION",
526
- level: "warning",
527
- message: `${message} (superseded by product-artifact diagnostic)`,
528
- });
529
- continue;
530
- }
531
399
  gaps.push({
532
400
  code: "DRAFT_VALIDATION",
533
401
  level: "blocking",
@@ -560,32 +428,13 @@ export async function prepareTaskSource(input) {
560
428
  .filter((gap) => gap.level === "blocking")
561
429
  .map((gap) => gap.code);
562
430
  const transactionIncomplete = blockingCodes.includes("TRANSACTION_INCOMPLETE");
563
- const productArtifactCodes = [
564
- "PRODUCT_ANALYSIS_NOT_EXECUTABLE",
565
- "PRODUCT_CLARIFICATION_NOT_EXECUTABLE",
566
- "PRODUCT_REQUIREMENT_PENDING",
567
- "PRODUCT_ARTIFACT_NOT_EXECUTABLE",
568
- ];
569
- const primaryBlockingCode = blockingCodes.find((code) => productArtifactCodes.includes(code)) ??
570
- blockingCodes.find((code) => code !== "EMPTY_ACCEPTANCE") ??
571
- blockingCodes[0] ??
572
- "INVALID_INPUT";
573
- // Soft intake only when PRD was imported (or product-artifact diagnostics apply).
574
- // Bare missing flags without import stay hard-invalid.
575
- const softIntakeOnly = blocking &&
576
- blockingCodes.length > 0 &&
577
- blockingCodes.every((code) => isIntakeSoftGapCode(code)) &&
578
- (hasImportedPrd ||
579
- blockingCodes.some((code) => productArtifactCodes.includes(code)));
580
431
  if (input.mode !== "apply") {
581
432
  return {
582
433
  ok: !blocking,
583
434
  outcome: blocking
584
435
  ? transactionIncomplete
585
436
  ? "needs-reconcile"
586
- : softIntakeOnly
587
- ? "blocked"
588
- : "invalid"
437
+ : "invalid"
589
438
  : "succeeded",
590
439
  mode: "dry-run",
591
440
  taskId,
@@ -603,13 +452,9 @@ export async function prepareTaskSource(input) {
603
452
  error: {
604
453
  code: transactionIncomplete
605
454
  ? "TRANSACTION_INCOMPLETE"
606
- : softIntakeOnly
607
- ? primaryBlockingCode
608
- : "INVALID_INPUT",
609
- message: softIntakeOnly
610
- ? "PRD imported or facts present but intake incomplete; DAG not generated"
611
- : "task source draft has blocking gaps",
612
- details: { gaps: blockingCodes, softIntake: softIntakeOnly },
455
+ : "INVALID_INPUT",
456
+ message: "task source draft has blocking gaps",
457
+ details: { gaps: blockingCodes },
613
458
  },
614
459
  }
615
460
  : {}),
@@ -641,9 +486,7 @@ export async function prepareTaskSource(input) {
641
486
  if (blocking) {
642
487
  const outcome = blockingCodes.includes("DIRTY_SOURCE")
643
488
  ? "blocked"
644
- : softIntakeOnly
645
- ? "blocked"
646
- : "invalid";
489
+ : "invalid";
647
490
  return {
648
491
  ok: false,
649
492
  outcome,
@@ -659,17 +502,10 @@ export async function prepareTaskSource(input) {
659
502
  contractStatus: state.effectiveStatus,
660
503
  warnings,
661
504
  error: {
662
- code: blockingCodes.includes("DIRTY_SOURCE")
663
- ? "DIRTY_SOURCE"
664
- : softIntakeOnly
665
- ? primaryBlockingCode
666
- : "INVALID_INPUT",
667
- message: softIntakeOnly
668
- ? "PRD imported or facts present but intake incomplete; DAG not generated"
669
- : "task source draft has blocking gaps",
505
+ code: outcome === "blocked" ? "DIRTY_SOURCE" : "INVALID_INPUT",
506
+ message: "task source draft has blocking gaps",
670
507
  details: {
671
508
  gaps: blockingCodes,
672
- softIntake: softIntakeOnly,
673
509
  },
674
510
  },
675
511
  };
@@ -5,16 +5,7 @@ import { getTaskPaths } from "../runtime.js";
5
5
  import { readSourceManifest, } from "../source-references.js";
6
6
  import { PREPARE_MAX_FILE_BYTES, PREPARE_MAX_PARSE_DOCS, PREPARE_MAX_TOTAL_BYTES, } from "./types.js";
7
7
  const PARSEABLE_EXTENSIONS = new Set([".md", ".markdown", ".txt"]);
8
- /** Roles that contribute requirement facts (objective/AC/scope). */
9
8
  const PARSEABLE_ROLES = new Set(["requirement", "acceptance"]);
10
- /** Roles whose body is loaded for artifact meta / diagnostics (not fact extraction). */
11
- const CONTENT_LOAD_ROLES = new Set([
12
- "requirement",
13
- "acceptance",
14
- "analysis",
15
- "clarification",
16
- "design",
17
- ]);
18
9
  function isSafeRelativeReferencePath(materializedPath) {
19
10
  const normalized = materializedPath.replace(/\\/g, "/").trim();
20
11
  if (!normalized)
@@ -61,12 +52,6 @@ function isParseableDoc(doc) {
61
52
  return false;
62
53
  return PARSEABLE_ROLES.has(doc.role);
63
54
  }
64
- function shouldLoadContent(doc) {
65
- const ext = path.extname(doc.materializedPath).toLowerCase();
66
- if (!PARSEABLE_EXTENSIONS.has(ext))
67
- return false;
68
- return CONTENT_LOAD_ROLES.has(doc.role) || PARSEABLE_ROLES.has(doc.role);
69
- }
70
55
  /**
71
56
  * Validate source-manifest + reference files before deriving a draft.
72
57
  * Fail-closed on taskId/path/hash/symlink/size issues.
@@ -185,7 +170,6 @@ export async function validateImportedPrdReferences(input) {
185
170
  continue;
186
171
  }
187
172
  const parseable = isParseableDoc(doc);
188
- const loadContent = shouldLoadContent(doc);
189
173
  if (parseable) {
190
174
  parseableCount += 1;
191
175
  if (parseableCount > PREPARE_MAX_PARSE_DOCS) {
@@ -199,7 +183,7 @@ export async function validateImportedPrdReferences(input) {
199
183
  }
200
184
  let hashResult;
201
185
  try {
202
- hashResult = await streamSha256AndBytes(absolutePath, loadContent ? PREPARE_MAX_FILE_BYTES : undefined);
186
+ hashResult = await streamSha256AndBytes(absolutePath, parseable ? PREPARE_MAX_FILE_BYTES : undefined);
203
187
  }
204
188
  catch (error) {
205
189
  if (error &&
@@ -239,7 +223,7 @@ export async function validateImportedPrdReferences(input) {
239
223
  });
240
224
  }
241
225
  let content;
242
- if (loadContent) {
226
+ if (parseable) {
243
227
  totalParseBytes += hashResult.bytes;
244
228
  if (totalParseBytes > PREPARE_MAX_TOTAL_BYTES) {
245
229
  issues.push({
@@ -36,7 +36,6 @@ export function openConsoleAppData(options) {
36
36
  drafts: path.join(repoNamespace, "drafts"),
37
37
  operations: path.join(repoNamespace, "operations"),
38
38
  confirmations: path.join(repoNamespace, "confirmations"),
39
- dagReceipts: path.join(repoNamespace, "dag-receipts"),
40
39
  staged: path.join(repoNamespace, "staged"),
41
40
  assessments: path.join(repoNamespace, "assessments"),
42
41
  interviews: path.join(repoNamespace, "interviews"),
@@ -48,7 +47,6 @@ export function openConsoleAppData(options) {
48
47
  paths.drafts,
49
48
  paths.operations,
50
49
  paths.confirmations,
51
- paths.dagReceipts,
52
50
  paths.staged,
53
51
  paths.assessments,
54
52
  paths.interviews,