@mjasnikovs/pi-task 0.37.7 → 0.38.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 (38) hide show
  1. package/dist/shared/child-output.d.ts +19 -3
  2. package/dist/shared/child-output.js +21 -5
  3. package/dist/shared/git-runner.d.ts +39 -0
  4. package/dist/shared/git-runner.js +38 -0
  5. package/dist/task/accept-debt.d.ts +27 -58
  6. package/dist/task/accept-debt.js +60 -130
  7. package/dist/task/auto-orchestrator.d.ts +7 -57
  8. package/dist/task/auto-orchestrator.js +25 -499
  9. package/dist/task/child-runner.d.ts +2 -0
  10. package/dist/task/child-runner.js +74 -70
  11. package/dist/task/enforce-guidelines.d.ts +1 -1
  12. package/dist/task/enforce-guidelines.js +2 -2
  13. package/dist/task/external-context.d.ts +85 -7
  14. package/dist/task/external-context.js +100 -63
  15. package/dist/task/file-inventory.js +22 -41
  16. package/dist/task/final-gate.d.ts +80 -0
  17. package/dist/task/final-gate.js +102 -49
  18. package/dist/task/gate-deps.js +6 -23
  19. package/dist/task/git-state-guard.d.ts +1 -1
  20. package/dist/task/git-state-guard.js +1 -7
  21. package/dist/task/phases.js +40 -83
  22. package/dist/task/run-final-gate.d.ts +127 -0
  23. package/dist/task/run-final-gate.js +492 -0
  24. package/dist/task/task-gates.d.ts +20 -57
  25. package/dist/task/task-gates.js +11 -11
  26. package/dist/task/verify-work.d.ts +40 -32
  27. package/dist/task/verify-work.js +301 -241
  28. package/dist/workers/docs-core.d.ts +14 -0
  29. package/dist/workers/docs-core.js +28 -16
  30. package/dist/workers/fetch-core.d.ts +6 -1
  31. package/dist/workers/fetch-core.js +26 -33
  32. package/dist/workers/focused-extractor.d.ts +73 -0
  33. package/dist/workers/focused-extractor.js +72 -0
  34. package/dist/workers/pi-worker-docs.d.ts +1 -1
  35. package/dist/workers/pi-worker-docs.js +48 -42
  36. package/dist/workers/pi-worker-fetch.js +6 -8
  37. package/dist/workers/typeonly-log.d.ts +13 -0
  38. package/package.json +1 -1
@@ -3,6 +3,11 @@ import { SessionUI } from '../remote/bridge.js';
3
3
  import { isYoloMode, yoloVerifyResolution, YOLO_STAMP } from './yolo.js';
4
4
  import { extractFailingCommand, findRepairCandidate, summariseDefect } from './root-cause-repair.js';
5
5
  import { attributeEnforceFailure } from './enforce-attribution.js';
6
+ // The debt ledger is reached through the injected `recordDebt` dep (so it stays
7
+ // absent-in-tests); only the origin TYPE and the cross-task-deletion reason SHAPE
8
+ // come from accept-debt.ts directly — the latter because its writer and its
9
+ // re-check-side parser (extractDeletedDebtPath) have to move together.
10
+ import { crossTaskDeletionReason } from './accept-debt.js';
6
11
  /**
7
12
  * How many times a verify FAIL may be auto-fixed UNATTENDED (the research
8
13
  * recommended AUTOFIX, so pi re-runs the impl turn without prompting) before the
@@ -115,7 +120,7 @@ export async function runGatesForTask(ctxIn, deps, p) {
115
120
  });
116
121
  if (!candidate)
117
122
  return null;
118
- await deps.recordRootCauseDebt?.(p.cwd, p.taskId, `${failReason} — ROOT CAUSE: \`${candidate.file}\` (introduced by ${candidate.owner}, not touched by this task)`);
123
+ await deps.recordDebt?.(p.cwd, p.taskId, `${failReason} — ROOT CAUSE: \`${candidate.file}\` (introduced by ${candidate.owner}, not touched by this task)`, 'root-cause');
119
124
  await deps.recordRepairCandidate?.(p.cwd, candidate);
120
125
  await rec(`root-cause: FAIL attributed to \`${candidate.file}\` — a pre-existing defect in ${candidate.owner}'s file that this task never touched; `
121
126
  + 'recorded as durable debt and a scoped repair task queued');
@@ -223,7 +228,7 @@ export async function runGatesForTask(ctxIn, deps, p) {
223
228
  // final gate must surface it at run end (static-class: it auto-closes
224
229
  // iff the run-end static check passes).
225
230
  try {
226
- await deps.recordFrozenBlockedDebt?.(p.cwd, p.taskId, `${failReason} — ${frozenContradiction}`);
231
+ await deps.recordDebt?.(p.cwd, p.taskId, `${failReason} — ${frozenContradiction}`, 'frozen-blocked');
227
232
  }
228
233
  catch {
229
234
  // recording must never break the gate sequence
@@ -310,12 +315,7 @@ export async function runGatesForTask(ctxIn, deps, p) {
310
315
  // Provenance splits here, mandatorily: an auto-pick writes the
311
316
  // 'yolo-accepted' origin, never the plain 'accepted' one that
312
317
  // asserts a human weighed the failing artifact.
313
- if (byYolo) {
314
- await deps.recordYoloAcceptDebt?.(p.cwd, p.taskId, failReason);
315
- }
316
- else {
317
- await deps.recordAcceptDebt?.(p.cwd, p.taskId, failReason);
318
- }
318
+ await deps.recordDebt?.(p.cwd, p.taskId, failReason, byYolo ? 'yolo-accepted' : 'accepted');
319
319
  }
320
320
  catch {
321
321
  // recording must never break the gate sequence
@@ -331,7 +331,7 @@ export async function runGatesForTask(ctxIn, deps, p) {
331
331
  // the final gate re-checks them (mx5 run 12 PROMPT 2). Best-effort.
332
332
  for (const del of verified.crossTaskDeletions ?? []) {
333
333
  try {
334
- await deps.recordCrossTaskDeletionDebt?.(p.cwd, p.taskId, del);
334
+ await deps.recordDebt?.(p.cwd, p.taskId, crossTaskDeletionReason(del), 'cross-task-deletion');
335
335
  await rec(`accept-debt: cross-task deletion recorded — ${del.path} (${del.owner}'s deliverable)`);
336
336
  }
337
337
  catch {
@@ -581,7 +581,7 @@ export async function runGatesForTask(ctxIn, deps, p) {
581
581
  // Keeping the edits must NOT lose the finding — that was mx5 run
582
582
  // 5's mistake. Same durability as the revert path; only the
583
583
  // disposition of the edits differs.
584
- await deps.recordEnforceKeptDebt?.(p.cwd, p.taskId, afterReason);
584
+ await deps.recordDebt?.(p.cwd, p.taskId, afterReason, 'enforce-kept');
585
585
  // …and, when the named file is somebody else's committed work,
586
586
  // queue the scoped repair so something actually FIXES it.
587
587
  if (attribution.file && deps.introducedBy && deps.recordRepairCandidate) {
@@ -622,7 +622,7 @@ export async function runGatesForTask(ctxIn, deps, p) {
622
622
  // erasing it with the enforce edits buried the terminal fault 8.5h
623
623
  // before run end. The final gate re-checks/surfaces it (static-class
624
624
  // auto-closes if a later task fixed the statics; else stays open).
625
- await deps.recordEnforceRevertDebt?.(p.cwd, p.taskId, after.reason ?? 'enforce re-verify failed');
625
+ await deps.recordDebt?.(p.cwd, p.taskId, after.reason ?? 'enforce re-verify failed', 'enforce-revert');
626
626
  active.ui.notify(`${p.tag}: guideline fixes regressed verification on "${p.title}" (${(after.reason ?? 'now fails').slice(0, 120)}) — ${deps.revert ? 'reverted them, kept the verified work' : 'left in place (no revert available)'}.`, 'warning');
627
627
  }
628
628
  else {
@@ -44,43 +44,51 @@ export interface VerifyOutcome {
44
44
  */
45
45
  export declare function extractSpecForVerification(taskBody: string): string | null;
46
46
  /**
47
- * Build the verification child's prompt. Kept pure so the wording is unit-tested
48
- * without spawning pi. The contract: run the spec's own verification in the real
49
- * workspace, judge against ACCEPTANCE, and end on exactly one verdict line.
47
+ * ─────────────────────────── THE PROBE TABLE ───────────────────────────
48
+ *
49
+ * Every deterministic probe that sharpens this prompt used to cost the same
50
+ * ritual in four places: a `let x = []` + try/catch in runWorkVerification, a
51
+ * positional parameter on buildVerifyPrompt, a `const xBlock =` ternary, and a
52
+ * spread into the assembled prompt — plus its hand-numbered rule. Adding one
53
+ * meant editing all of them and hoping none was missed; the ninth would not
54
+ * even fit the signature (hence the `projectSurface` bag that used to group
55
+ * three of them).
50
56
  *
51
- * `probeFindings` are the deterministic self-verification probe results (see
52
- * substitution-probe.ts): the TEST-THE-COPY class is caught 5/5 only when the
53
- * prompt carries both the rule (3b) AND a concrete finding naming the suspect
54
- * file the rule alone got 2/5 attention on the local model. The findings are
55
- * pure git shape (test files the task itself changed), so the mandate is
56
- * language- and framework-agnostic.
57
+ * Each probe is now an ADAPTER: one row carrying only what is specific to it —
58
+ * the dep field it reads, the empty value it degrades to, how its raw result
59
+ * becomes finding lines, the notice block those lines produce, and the numbered
60
+ * rule the notice routes the child to. The loop owns the ritual. (Same shape as
61
+ * LOCKFILE_CHECKS in final-gate.ts, where a whole package ecosystem is one row.)
57
62
  *
58
- * `prohibitionFindings` are the deterministic prohibition probe results (see
59
- * prohibition-probe.ts): spec-forbidden paths the task's diff modified anyway.
60
- * Same probe+rule design, same reason: the VIOLATION-EXCUSAL class (mx5 run 7:
61
- * child saw "Do NOT modify server-side code" violated, waived it as "additive,
62
- * tests pass", PASSed) needs both the no-waiver rule (4b) AND the concrete diff
63
- * fact the baseline child usually never runs `git diff` at all, so without the
64
- * finding it cannot even SEE the violation. A/B on the live local model
65
- * (violated-but-working fixture, everything green, forbidden file modified
66
- * additively): old prompt 5/5 false-PASS (several runs affirmatively claimed the
67
- * forbidden file was untouched); rule+finding 5/5 FAIL naming the constraint.
68
- * Guard: honest-clean fixture (prohibition in spec, probe silent) 5/5 PASS — no
69
- * paranoia. Reverted-violation ≡ clean at the diff level (no entry → no finding).
63
+ * THIS PROMPT IS A MEASURED ARTIFACT its wording is A/B-tested on the live
64
+ * local model and the verdicts are recorded in VALIDATION-DEBT.md, so the table
65
+ * must emit BYTE-IDENTICAL text for the same findings. Two orders are
66
+ * load-bearing and they are NOT the same order:
67
+ * - NOTICE BLOCKS are emitted in TABLE order (the order the rows appear below).
68
+ * - RULES are emitted sorted by `ruleId`, because the 4b…4g band was
69
+ * hand-numbered long before this table existed and its numbering is what the
70
+ * notices cite ("rule 4b applies").
71
+ * A row whose rule is woven into the numbered narrative elsewhere (3b inside the
72
+ * substitution rules, 3f, 5c) carries `ruleId` for the reader and no `rule` text.
70
73
  */
71
- export declare function buildVerifyPrompt(spec: string, probeFindings?: string[], envNotes?: string, prohibitionFindings?: string[], skipEscapeFindings?: string[], contracts?: string, testAssemblyFindings?: string[], probeGamingFindings?: string[], crossTaskDeletionFindings?: string[],
74
+ /** Stable identity of one probe channel: table row findings-bag key. */
75
+ export type ProbeKey = 'substitution' | 'prohibition' | 'crossTaskDeletion' | 'probeGaming' | 'skipEscape' | 'foreignPath' | 'scriptEscape' | 'runnerGlob' | 'testAssembly';
76
+ /** The finding lines each probe channel contributed. Absent/empty ⇒ no block. */
77
+ export type ProbeFindings = Partial<Record<ProbeKey, string[]>>;
72
78
  /**
73
- * The mx5 run-13 (PROMPT 4) probes, grouped rather than appended as three more
74
- * positional parameters this signature was already at its limit. Each key is
75
- * an independent finding list; absent/empty emits no block.
79
+ * Build the verification child's prompt. Kept pure so the wording is unit-tested
80
+ * without spawning pi. The contract: run the spec's own verification in the real
81
+ * workspace, judge against ACCEPTANCE, and end on exactly one verdict line.
82
+ *
83
+ * `findings` is the probe bag: one key per PROBE_ADAPTERS row (see the table
84
+ * above for what each channel means and the A/B evidence behind it). A key that
85
+ * is absent or empty emits no block — the probes are independently optional.
76
86
  */
77
- projectSurface?: {
78
- /** Sandbox-leaked absolute paths (rule 4e) — see foreign-path.ts. */
79
- foreignPaths?: string[];
80
- /** Check scripts that cannot fail (rule 4f) — see script-escape.ts. */
81
- scriptEscapes?: string[];
82
- /** Colliding test-runner globs (rule 4g) — see runner-globs.ts. */
83
- runnerGlobs?: string[];
87
+ export declare function buildVerifyPrompt(spec: string, findings?: ProbeFindings, context?: {
88
+ /** Environment facts earlier gate children discovered — see env-notes.ts. */
89
+ envNotes?: string;
90
+ /** Cross-slice interface facts the design pins — see contracts.ts. */
91
+ contracts?: string;
84
92
  }): string;
85
93
  /**
86
94
  * Parse the child's verdict. Scans for the LAST `WORK-VERIFIED: PASS|FAIL|UNOBSERVED`