@phamvuhoang/otto-core 0.21.0 → 0.22.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 (42) hide show
  1. package/dist/index.d.ts +5 -4
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +5 -4
  4. package/dist/index.js.map +1 -1
  5. package/dist/loop.d.ts.map +1 -1
  6. package/dist/loop.js +200 -16
  7. package/dist/loop.js.map +1 -1
  8. package/dist/plan-artifacts.d.ts +10 -0
  9. package/dist/plan-artifacts.d.ts.map +1 -0
  10. package/dist/plan-artifacts.js +63 -0
  11. package/dist/plan-artifacts.js.map +1 -0
  12. package/dist/plan-gate.d.ts +10 -1
  13. package/dist/plan-gate.d.ts.map +1 -1
  14. package/dist/plan-gate.js +22 -4
  15. package/dist/plan-gate.js.map +1 -1
  16. package/dist/plan-report-cli.d.ts +2 -1
  17. package/dist/plan-report-cli.d.ts.map +1 -1
  18. package/dist/plan-report-cli.js +9 -32
  19. package/dist/plan-report-cli.js.map +1 -1
  20. package/dist/plan-rubric.d.ts +24 -0
  21. package/dist/plan-rubric.d.ts.map +1 -1
  22. package/dist/plan-rubric.js +122 -0
  23. package/dist/plan-rubric.js.map +1 -1
  24. package/dist/report-finalize.d.ts +26 -0
  25. package/dist/report-finalize.d.ts.map +1 -0
  26. package/dist/report-finalize.js +222 -0
  27. package/dist/report-finalize.js.map +1 -0
  28. package/dist/report-rubric.d.ts +1 -1
  29. package/dist/report-rubric.d.ts.map +1 -1
  30. package/dist/report-rubric.js +3 -3
  31. package/dist/report-rubric.js.map +1 -1
  32. package/dist/runner.d.ts +2 -0
  33. package/dist/runner.d.ts.map +1 -1
  34. package/dist/runner.js +1 -1
  35. package/dist/runner.js.map +1 -1
  36. package/dist/stage-exec.d.ts.map +1 -1
  37. package/dist/stage-exec.js +3 -2
  38. package/dist/stage-exec.js.map +1 -1
  39. package/package.json +1 -1
  40. package/templates/plan.md +36 -4
  41. package/templates/quality-report.md +18 -9
  42. package/templates/report-rewrite.md +25 -0
@@ -0,0 +1,63 @@
1
+ import { readFileSync, readdirSync, statSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ function readOptional(path) {
4
+ try {
5
+ return readFileSync(path, "utf8");
6
+ }
7
+ catch {
8
+ return "";
9
+ }
10
+ }
11
+ function updatedMs(paths) {
12
+ let latest = 0;
13
+ for (const p of paths) {
14
+ try {
15
+ latest = Math.max(latest, statSync(p).mtimeMs);
16
+ }
17
+ catch {
18
+ // Missing spec.md or plan.md is fine; callers score whatever exists.
19
+ }
20
+ }
21
+ return latest;
22
+ }
23
+ export function readTaskPlanDocuments(workspaceDir) {
24
+ const tasksDir = join(workspaceDir, ".otto", "tasks");
25
+ let entries;
26
+ try {
27
+ entries = readdirSync(tasksDir, { withFileTypes: true })
28
+ .filter((e) => e.isDirectory())
29
+ .map((e) => e.name)
30
+ .sort();
31
+ }
32
+ catch {
33
+ return [];
34
+ }
35
+ const docs = [];
36
+ for (const taskKey of entries) {
37
+ const specPath = join(".otto", "tasks", taskKey, "spec.md");
38
+ const planPath = join(".otto", "tasks", taskKey, "plan.md");
39
+ const absSpec = join(workspaceDir, specPath);
40
+ const absPlan = join(workspaceDir, planPath);
41
+ const doc = [readOptional(absSpec), readOptional(absPlan)].join("\n");
42
+ if (doc.trim() === "")
43
+ continue;
44
+ docs.push({
45
+ taskKey,
46
+ specPath,
47
+ planPath,
48
+ doc,
49
+ updatedMs: updatedMs([absSpec, absPlan]),
50
+ });
51
+ }
52
+ return docs;
53
+ }
54
+ export function latestTaskPlanDocument(workspaceDir) {
55
+ const docs = readTaskPlanDocuments(workspaceDir);
56
+ if (docs.length === 0)
57
+ return null;
58
+ return docs
59
+ .slice()
60
+ .sort((a, b) => a.updatedMs - b.updatedMs || a.taskKey.localeCompare(b.taskKey))
61
+ .at(-1);
62
+ }
63
+ //# sourceMappingURL=plan-artifacts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-artifacts.js","sourceRoot":"","sources":["../src/plan-artifacts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC9D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAUjC,SAAS,YAAY,CAAC,IAAY;IAChC,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,SAAS,SAAS,CAAC,KAAe;IAChC,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC;YACH,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;QACjD,CAAC;QAAC,MAAM,CAAC;YACP,qEAAqE;QACvE,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,YAAoB;IAEpB,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IACtD,IAAI,OAAiB,CAAC;IACtB,IAAI,CAAC;QACH,OAAO,GAAG,WAAW,CAAC,QAAQ,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;aACrD,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;aAC9B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;aAClB,IAAI,EAAE,CAAC;IACZ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,IAAI,GAAuB,EAAE,CAAC;IACpC,KAAK,MAAM,OAAO,IAAI,OAAO,EAAE,CAAC;QAC9B,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;QAC5D,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;QAC5D,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;QAC7C,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;QAC7C,MAAM,GAAG,GAAG,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtE,IAAI,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE;YAAE,SAAS;QAChC,IAAI,CAAC,IAAI,CAAC;YACR,OAAO;YACP,QAAQ;YACR,QAAQ;YACR,GAAG;YACH,SAAS,EAAE,SAAS,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;SACzC,CAAC,CAAC;IACL,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,YAAoB;IAEpB,MAAM,IAAI,GAAG,qBAAqB,CAAC,YAAY,CAAC,CAAC;IACjD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,OAAO,IAAI;SACR,KAAK,EAAE;SACP,IAAI,CACH,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,CAC1E;SACA,EAAE,CAAC,CAAC,CAAC,CAAE,CAAC;AACb,CAAC"}
@@ -7,13 +7,14 @@
7
7
  * `--plan-report` quality flag. Pure: takes a {@link PlanRubricScore}, returns the
8
8
  * verdict; triggers no re-plan itself (loop wiring is a follow-up).
9
9
  */
10
- import type { PlanRubricScore } from "./plan-rubric.js";
10
+ import type { PlanDepthScore, PlanRubricScore } from "./plan-rubric.js";
11
11
  /**
12
12
  * Default ratio a plan must reach to clear the gate. 0.75 = three-quarters of the
13
13
  * rubric criteria; tuned so a plan missing one or two sections still passes but a
14
14
  * thin plan (no scope guard, no tasks, no verify) does not.
15
15
  */
16
16
  export declare const DEFAULT_PLAN_QUALITY_THRESHOLD = 0.75;
17
+ export declare const DEFAULT_PLAN_DEPTH_THRESHOLD = 1;
17
18
  export type PlanGateVerdict = {
18
19
  passed: boolean;
19
20
  /** The plan's rubric ratio (0..1). */
@@ -24,6 +25,12 @@ export type PlanGateVerdict = {
24
25
  missing: string[];
25
26
  /** Criteria still needed to reach the threshold; 0 when passed. */
26
27
  shortfall: number;
28
+ /** Optional depth-gate ratio when a caller supplies the P13 depth score. */
29
+ depthRatio?: number;
30
+ /** Depth threshold applied, when present. */
31
+ depthThreshold?: number;
32
+ /** Depth criteria missing, when present. */
33
+ depthMissing?: string[];
27
34
  };
28
35
  /**
29
36
  * Assess a rubric score against the quality threshold. A plan passes when its
@@ -32,6 +39,8 @@ export type PlanGateVerdict = {
32
39
  */
33
40
  export declare function assessPlanGate(score: PlanRubricScore, opts?: {
34
41
  threshold?: number;
42
+ depth?: PlanDepthScore;
43
+ depthThreshold?: number;
35
44
  }): PlanGateVerdict;
36
45
  /**
37
46
  * Render a gate verdict: a `PASS`/`FAIL` line with the ratio vs threshold, and —
@@ -1 +1 @@
1
- {"version":3,"file":"plan-gate.d.ts","sourceRoot":"","sources":["../src/plan-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAExD;;;;GAIG;AACH,eAAO,MAAM,8BAA8B,OAAO,CAAC;AAEnD,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,OAAO,CAAC;IAChB,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,6BAA6B;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,0DAA0D;IAC1D,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,mEAAmE;IACnE,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,eAAe,EACtB,IAAI,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GAChC,eAAe,CAWjB;AAID;;;GAGG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,eAAe,GAAG,MAAM,CASzD"}
1
+ {"version":3,"file":"plan-gate.d.ts","sourceRoot":"","sources":["../src/plan-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAExE;;;;GAIG;AACH,eAAO,MAAM,8BAA8B,OAAO,CAAC;AACnD,eAAO,MAAM,4BAA4B,IAAI,CAAC;AAE9C,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,OAAO,CAAC;IAChB,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,6BAA6B;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,0DAA0D;IAC1D,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,mEAAmE;IACnE,SAAS,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6CAA6C;IAC7C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,4CAA4C;IAC5C,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,eAAe,EACtB,IAAI,GAAE;IACJ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;CACpB,GACL,eAAe,CAoBjB;AAID;;;GAGG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,eAAe,GAAG,MAAM,CAqBzD"}
package/dist/plan-gate.js CHANGED
@@ -13,6 +13,7 @@
13
13
  * thin plan (no scope guard, no tasks, no verify) does not.
14
14
  */
15
15
  export const DEFAULT_PLAN_QUALITY_THRESHOLD = 0.75;
16
+ export const DEFAULT_PLAN_DEPTH_THRESHOLD = 1;
16
17
  /**
17
18
  * Assess a rubric score against the quality threshold. A plan passes when its
18
19
  * ratio is at or above the threshold; otherwise `shortfall` is how many more
@@ -20,14 +21,23 @@ export const DEFAULT_PLAN_QUALITY_THRESHOLD = 0.75;
20
21
  */
21
22
  export function assessPlanGate(score, opts = {}) {
22
23
  const threshold = opts.threshold ?? DEFAULT_PLAN_QUALITY_THRESHOLD;
23
- const passed = score.ratio >= threshold;
24
+ const depthThreshold = opts.depthThreshold ?? DEFAULT_PLAN_DEPTH_THRESHOLD;
25
+ const depthPassed = opts.depth ? opts.depth.ratio >= depthThreshold : true;
26
+ const passed = score.ratio >= threshold && depthPassed;
24
27
  const needed = Math.ceil(threshold * score.maxScore) - score.metCount;
25
28
  return {
26
29
  passed,
27
30
  ratio: score.ratio,
28
31
  threshold,
29
32
  missing: score.missing,
30
- shortfall: passed ? 0 : Math.max(0, needed),
33
+ shortfall: score.ratio >= threshold ? 0 : Math.max(0, needed),
34
+ ...(opts.depth
35
+ ? {
36
+ depthRatio: opts.depth.ratio,
37
+ depthThreshold,
38
+ depthMissing: opts.depth.missing,
39
+ }
40
+ : {}),
31
41
  };
32
42
  }
33
43
  const pct = new Intl.NumberFormat("en-US", { maximumFractionDigits: 0 });
@@ -40,7 +50,15 @@ export function formatPlanGate(v) {
40
50
  `(${pct.format(v.ratio * 100)}% vs ${pct.format(v.threshold * 100)}% threshold)`;
41
51
  if (v.passed)
42
52
  return head;
43
- return (head +
44
- `\n re-plan to add ${v.shortfall} more: ${v.missing.join(", ") || "—"}`);
53
+ const lines = [head];
54
+ if (v.shortfall > 0) {
55
+ lines.push(` re-plan to add ${v.shortfall} more: ${v.missing.join(", ") || "—"}`);
56
+ }
57
+ if (v.depthRatio != null &&
58
+ v.depthThreshold != null &&
59
+ v.depthRatio < v.depthThreshold) {
60
+ lines.push(` deepen plan: ${pct.format(v.depthRatio * 100)}% vs ${pct.format(v.depthThreshold * 100)}% depth threshold; missing ${v.depthMissing?.join(", ") || "—"}`);
61
+ }
62
+ return lines.join("\n");
45
63
  }
46
64
  //# sourceMappingURL=plan-gate.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"plan-gate.js","sourceRoot":"","sources":["../src/plan-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH;;;;GAIG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG,IAAI,CAAC;AAcnD;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAC5B,KAAsB,EACtB,OAA+B,EAAE;IAEjC,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,8BAA8B,CAAC;IACnE,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,IAAI,SAAS,CAAC;IACxC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,QAAQ,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC;IACtE,OAAO;QACL,MAAM;QACN,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,SAAS;QACT,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC;KAC5C,CAAC;AACJ,CAAC;AAED,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,EAAE,qBAAqB,EAAE,CAAC,EAAE,CAAC,CAAC;AAEzE;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,CAAkB;IAC/C,MAAM,IAAI,GACR,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,GAAG;QAC3C,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,GAAG,GAAG,CAAC,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,GAAG,GAAG,CAAC,cAAc,CAAC;IACnF,IAAI,CAAC,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAC1B,OAAO,CACL,IAAI;QACJ,sBAAsB,CAAC,CAAC,SAAS,UAAU,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,EAAE,CACzE,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"plan-gate.js","sourceRoot":"","sources":["../src/plan-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH;;;;GAIG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG,IAAI,CAAC;AACnD,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,CAAC;AAoB9C;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAC5B,KAAsB,EACtB,OAII,EAAE;IAEN,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,8BAA8B,CAAC;IACnE,MAAM,cAAc,GAAG,IAAI,CAAC,cAAc,IAAI,4BAA4B,CAAC;IAC3E,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC;IAC3E,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,IAAI,SAAS,IAAI,WAAW,CAAC;IACvD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,QAAQ,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC;IACtE,OAAO;QACL,MAAM;QACN,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,SAAS;QACT,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,SAAS,EAAE,KAAK,CAAC,KAAK,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC;QAC7D,GAAG,CAAC,IAAI,CAAC,KAAK;YACZ,CAAC,CAAC;gBACE,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK;gBAC5B,cAAc;gBACd,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO;aACjC;YACH,CAAC,CAAC,EAAE,CAAC;KACR,CAAC;AACJ,CAAC;AAED,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,EAAE,qBAAqB,EAAE,CAAC,EAAE,CAAC,CAAC;AAEzE;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,CAAkB;IAC/C,MAAM,IAAI,GACR,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,GAAG;QAC3C,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,GAAG,GAAG,CAAC,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,GAAG,GAAG,CAAC,cAAc,CAAC;IACnF,IAAI,CAAC,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAC1B,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,CAAC;IACrB,IAAI,CAAC,CAAC,SAAS,GAAG,CAAC,EAAE,CAAC;QACpB,KAAK,CAAC,IAAI,CACR,oBAAoB,CAAC,CAAC,SAAS,UAAU,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,EAAE,CACvE,CAAC;IACJ,CAAC;IACD,IACE,CAAC,CAAC,UAAU,IAAI,IAAI;QACpB,CAAC,CAAC,cAAc,IAAI,IAAI;QACxB,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,cAAc,EAC/B,CAAC;QACD,KAAK,CAAC,IAAI,CACR,kBAAkB,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,GAAG,GAAG,CAAC,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc,GAAG,GAAG,CAAC,8BAA8B,CAAC,CAAC,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,EAAE,CAC5J,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
@@ -1,4 +1,4 @@
1
- import { type PlanRubricScore } from "./plan-rubric.js";
1
+ import { type PlanDepthScore, type PlanRubricScore } from "./plan-rubric.js";
2
2
  /**
3
3
  * `otto-afk --plan-report` read-only surface (issue #63 P8, slice 3).
4
4
  *
@@ -19,6 +19,7 @@ export type PlanReportDeps = {
19
19
  export type TaskPlanScore = {
20
20
  taskKey: string;
21
21
  score: PlanRubricScore;
22
+ depth: PlanDepthScore;
22
23
  };
23
24
  /**
24
25
  * Render the per-task plan scorecards into one report. Pure: takes the already
@@ -1 +1 @@
1
- {"version":3,"file":"plan-report-cli.d.ts","sourceRoot":"","sources":["../src/plan-report-cli.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,kBAAkB,CAAC;AAE1B;;;;;;;;GAQG;AAEH,4FAA4F;AAC5F,MAAM,MAAM,cAAc,GAAG;IAC3B,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3B,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC5B,CAAC;AASF,qDAAqD;AACrD,MAAM,MAAM,aAAa,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,eAAe,CAAA;CAAE,CAAC;AAExE;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,MAAM,CAW/D;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,aAAa,EAAE,CA0BnE;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,IAAI,GAAE,cAA4B,GACjC,OAAO,CAAC,MAAM,CAAC,CAYjB"}
1
+ {"version":3,"file":"plan-report-cli.d.ts","sourceRoot":"","sources":["../src/plan-report-cli.ts"],"names":[],"mappings":"AAIA,OAAO,EAKL,KAAK,cAAc,EACnB,KAAK,eAAe,EACrB,MAAM,kBAAkB,CAAC;AAE1B;;;;;;;;GAQG;AAEH,4FAA4F;AAC5F,MAAM,MAAM,cAAc,GAAG;IAC3B,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3B,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC5B,CAAC;AASF,qDAAqD;AACrD,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,eAAe,CAAC;IACvB,KAAK,EAAE,cAAc,CAAC;CACvB,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,MAAM,CAY/D;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,aAAa,EAAE,CAMnE;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,IAAI,GAAE,cAA4B,GACjC,OAAO,CAAC,MAAM,CAAC,CAYjB"}
@@ -1,7 +1,7 @@
1
- import { readFileSync, readdirSync } from "node:fs";
2
- import { join, resolve } from "node:path";
1
+ import { resolve } from "node:path";
3
2
  import { assessPlanGate, formatPlanGate } from "./plan-gate.js";
4
- import { formatPlanRubric, scorePlanQuality, } from "./plan-rubric.js";
3
+ import { readTaskPlanDocuments } from "./plan-artifacts.js";
4
+ import { formatPlanDepthRubric, formatPlanRubric, scorePlanDepth, scorePlanQuality, } from "./plan-rubric.js";
5
5
  const defaultDeps = {
6
6
  env: process.env,
7
7
  cwd: process.cwd(),
@@ -16,7 +16,7 @@ const defaultDeps = {
16
16
  export function formatPlanReport(tasks) {
17
17
  const lines = ["Plan report"];
18
18
  for (const t of tasks) {
19
- lines.push("", `Task ${t.taskKey}`, formatPlanRubric(t.score), formatPlanGate(assessPlanGate(t.score)));
19
+ lines.push("", `Task ${t.taskKey}`, formatPlanRubric(t.score), formatPlanDepthRubric(t.depth), formatPlanGate(assessPlanGate(t.score, { depth: t.depth })));
20
20
  }
21
21
  return lines.join("\n");
22
22
  }
@@ -27,34 +27,11 @@ export function formatPlanReport(tasks) {
27
27
  * {@link formatPlanReport} stays pure. Absent/unreadable dir → `[]`.
28
28
  */
29
29
  export function readTaskPlans(workspaceDir) {
30
- const tasksDir = join(workspaceDir, ".otto", "tasks");
31
- let entries;
32
- try {
33
- entries = readdirSync(tasksDir, { withFileTypes: true })
34
- .filter((e) => e.isDirectory())
35
- .map((e) => e.name)
36
- .sort();
37
- }
38
- catch {
39
- return [];
40
- }
41
- const scored = [];
42
- for (const taskKey of entries) {
43
- const doc = ["spec.md", "plan.md"]
44
- .map((f) => {
45
- try {
46
- return readFileSync(join(tasksDir, taskKey, f), "utf8");
47
- }
48
- catch {
49
- return "";
50
- }
51
- })
52
- .join("\n");
53
- if (doc.trim() === "")
54
- continue;
55
- scored.push({ taskKey, score: scorePlanQuality(doc) });
56
- }
57
- return scored;
30
+ return readTaskPlanDocuments(workspaceDir).map((task) => ({
31
+ taskKey: task.taskKey,
32
+ score: scorePlanQuality(task.doc),
33
+ depth: scorePlanDepth(task.doc),
34
+ }));
58
35
  }
59
36
  /**
60
37
  * Drive `--plan-report`: score every authored task plan under `.otto/tasks/` and
@@ -1 +1 @@
1
- {"version":3,"file":"plan-report-cli.js","sourceRoot":"","sources":["../src/plan-report-cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"plan-report-cli.js","sourceRoot":"","sources":["../src/plan-report-cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EACL,qBAAqB,EACrB,gBAAgB,EAChB,cAAc,EACd,gBAAgB,GAGjB,MAAM,kBAAkB,CAAC;AAoB1B,MAAM,WAAW,GAAmB;IAClC,GAAG,EAAE,OAAO,CAAC,GAAG;IAChB,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;IAClB,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;IAC1C,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;CAC3C,CAAC;AASF;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAsB;IACrD,MAAM,KAAK,GAAa,CAAC,aAAa,CAAC,CAAC;IACxC,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,KAAK,CAAC,IAAI,CACR,EAAE,EACF,QAAQ,CAAC,CAAC,OAAO,EAAE,EACnB,gBAAgB,CAAC,CAAC,CAAC,KAAK,CAAC,EACzB,qBAAqB,CAAC,CAAC,CAAC,KAAK,CAAC,EAC9B,cAAc,CAAC,cAAc,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAC5D,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,YAAoB;IAChD,OAAO,qBAAqB,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACxD,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,KAAK,EAAE,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC;QACjC,KAAK,EAAE,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC;KAChC,CAAC,CAAC,CAAC;AACN,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,OAAuB,WAAW;IAElC,MAAM,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,cAAc,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;IAClE,MAAM,KAAK,GAAG,aAAa,CAAC,YAAY,CAAC,CAAC;IAC1C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,IAAI,CAAC,GAAG,CACN,6BAA6B,YAAY,iBAAiB;YACxD,iEAAiE,CACpE,CAAC;QACF,OAAO,CAAC,CAAC;IACX,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC;IAClC,OAAO,CAAC,CAAC;AACX,CAAC"}
@@ -51,6 +51,30 @@ export type PlanRubricScore = {
51
51
  /** Labels of unmet criteria — the "what to improve" surface. */
52
52
  missing: string[];
53
53
  };
54
+ export type PlanDepthCriterion = "realFileMap" | "taskTestAndVerify" | "testableSuccessCriteria";
55
+ export type PlanDepthCriterionResult = {
56
+ criterion: PlanDepthCriterion;
57
+ label: string;
58
+ met: boolean;
59
+ detail: string;
60
+ };
61
+ export type PlanDepthScore = {
62
+ results: PlanDepthCriterionResult[];
63
+ metCount: number;
64
+ maxScore: number;
65
+ ratio: number;
66
+ missing: string[];
67
+ fileMap: string[];
68
+ };
69
+ export declare function extractPlanFileMap(doc: string): string[];
70
+ export declare function scorePlanDepth(doc: string): PlanDepthScore;
71
+ export declare function formatPlanDepthRubric(score: PlanDepthScore): string;
72
+ export type ScopeDriftResult = {
73
+ plannedFiles: string[];
74
+ touchedFiles: string[];
75
+ outOfScope: string[];
76
+ };
77
+ export declare function detectScopeDrift(planDoc: string, touchedFiles: string[]): ScopeDriftResult;
54
78
  /**
55
79
  * Score a spec/plan markdown document against {@link PLAN_CRITERIA}. Pure and
56
80
  * deterministic — pass the spec text, the plan text, or both concatenated. Each
@@ -1 +1 @@
1
- {"version":3,"file":"plan-rubric.d.ts","sourceRoot":"","sources":["../src/plan-rubric.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,MAAM,MAAM,aAAa,GACrB,SAAS,GACT,WAAW,GACX,YAAY,GACZ,SAAS,GACT,eAAe,GACf,WAAW,GACX,gBAAgB,GAChB,iBAAiB,CAAC;AAEtB,KAAK,YAAY,GAAG;IAClB,SAAS,EAAE,aAAa,CAAC;IACzB,8CAA8C;IAC9C,KAAK,EAAE,MAAM,CAAC;IACd,gEAAgE;IAChE,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;CAClC,CAAC;AAeF;;;;GAIG;AACH,eAAO,MAAM,aAAa,EAAE,aAAa,CAAC,YAAY,CA6DrD,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,SAAS,EAAE,aAAa,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,OAAO,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,uDAAuD;IACvD,OAAO,EAAE,mBAAmB,EAAE,CAAC;IAC/B,oBAAoB;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,wCAAwC;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,iEAAiE;IACjE,KAAK,EAAE,MAAM,CAAC;IACd,gEAAgE;IAChE,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,CAe7D;AAID;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAU/D"}
1
+ {"version":3,"file":"plan-rubric.d.ts","sourceRoot":"","sources":["../src/plan-rubric.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,MAAM,MAAM,aAAa,GACrB,SAAS,GACT,WAAW,GACX,YAAY,GACZ,SAAS,GACT,eAAe,GACf,WAAW,GACX,gBAAgB,GAChB,iBAAiB,CAAC;AAEtB,KAAK,YAAY,GAAG;IAClB,SAAS,EAAE,aAAa,CAAC;IACzB,8CAA8C;IAC9C,KAAK,EAAE,MAAM,CAAC;IACd,gEAAgE;IAChE,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;CAClC,CAAC;AAeF;;;;GAIG;AACH,eAAO,MAAM,aAAa,EAAE,aAAa,CAAC,YAAY,CA6DrD,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,SAAS,EAAE,aAAa,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,OAAO,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,uDAAuD;IACvD,OAAO,EAAE,mBAAmB,EAAE,CAAC;IAC/B,oBAAoB;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,wCAAwC;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,iEAAiE;IACjE,KAAK,EAAE,MAAM,CAAC;IACd,gEAAgE;IAChE,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAC1B,aAAa,GACb,mBAAmB,GACnB,yBAAyB,CAAC;AAE9B,MAAM,MAAM,wBAAwB,GAAG;IACrC,SAAS,EAAE,kBAAkB,CAAC;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,EAAE,wBAAwB,EAAE,CAAC;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AAWF,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAQxD;AAoCD,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAkD1D;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CAUnE;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB,CAAC;AAQF,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EAAE,GACrB,gBAAgB,CAmBlB;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,CAe7D;AAID;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAQ/D"}
@@ -81,6 +81,128 @@ export const PLAN_CRITERIA = [
81
81
  detect: (d) => /\b(?:success (?:criteria|metric)|acceptance (?:criteria|checklist|test)|done when|testing notes|testable)\b/i.test(d),
82
82
  },
83
83
  ];
84
+ const REAL_PATH_RE = /`([^`\n]*(?:\/[^`\n]*|\.(?:ts|tsx|js|jsx|mjs|cjs|md|json|py|go|rs|java|rb|sh))[^\n`]*)`/gi;
85
+ const TEST_FILE_RE = /\b(?:__tests__\/\S+|\S+\.(?:test|spec)\.(?:ts|tsx|js|jsx|mjs|cjs)|\S+_test\.(?:go|py)|tests?\/\S+)\b/i;
86
+ const VERIFY_CMD_RE = /\bverify:\s*`?[^`\n]*(?:pnpm|npm run|vitest|tsc|node --test|node --|pytest|go test|cargo test|make)[^`\n]*`?/i;
87
+ const FAILING_TEST_RE = /\b(?:failing test|test[- ]first|tdd|red[- ]green|write (?:a |the )?(?:failing )?test|tests? (?:first|before)|pinned by)\b/i;
88
+ export function extractPlanFileMap(doc) {
89
+ const paths = new Set();
90
+ for (const match of doc.matchAll(REAL_PATH_RE)) {
91
+ const p = match[1].trim();
92
+ if (!p || /^https?:\/\//i.test(p))
93
+ continue;
94
+ paths.add(p.replace(/^\.\//, ""));
95
+ }
96
+ return [...paths].sort();
97
+ }
98
+ function taskBlocks(doc) {
99
+ const lines = doc.split("\n");
100
+ const blocks = [];
101
+ let cur = [];
102
+ const startsTask = (line) => /^\s*[-*]\s*\[[ xX]\]\s+\S/.test(line) || /^\s*\d+\.\s+\S/.test(line);
103
+ const flush = () => {
104
+ if (cur.length > 0)
105
+ blocks.push(cur.join("\n"));
106
+ cur = [];
107
+ };
108
+ for (const line of lines) {
109
+ if (startsTask(line)) {
110
+ flush();
111
+ cur.push(line);
112
+ }
113
+ else if (cur.length > 0) {
114
+ if (/^\S/.test(line) && line.trim() !== "")
115
+ flush();
116
+ else
117
+ cur.push(line);
118
+ }
119
+ }
120
+ flush();
121
+ return blocks;
122
+ }
123
+ function successSection(doc) {
124
+ const m = /(?:^|\n)#{1,6}\s+[^\n]*(?:success criteria|acceptance criteria|testing notes)[^\n]*\n/i.exec(doc);
125
+ if (!m)
126
+ return "";
127
+ const rest = doc.slice(m.index + m[0].length);
128
+ const next = /(?:^|\n)#{1,6}\s+/.exec(rest);
129
+ return next ? rest.slice(0, next.index) : rest;
130
+ }
131
+ export function scorePlanDepth(doc) {
132
+ const fileMap = extractPlanFileMap(doc);
133
+ const tasks = taskBlocks(doc);
134
+ const badTasks = tasks.filter((t) => !FAILING_TEST_RE.test(t) ||
135
+ !TEST_FILE_RE.test(t) ||
136
+ !VERIFY_CMD_RE.test(t));
137
+ const success = successSection(doc);
138
+ const results = [
139
+ {
140
+ criterion: "realFileMap",
141
+ label: "File map names at least two real paths",
142
+ met: fileMap.length >= 2,
143
+ detail: `${fileMap.length} path(s) found`,
144
+ },
145
+ {
146
+ criterion: "taskTestAndVerify",
147
+ label: "Each task names a failing test and verify command",
148
+ met: tasks.length > 0 && badTasks.length === 0,
149
+ detail: tasks.length === 0
150
+ ? "no task blocks found"
151
+ : `${tasks.length - badTasks.length}/${tasks.length} task(s) deep enough`,
152
+ },
153
+ {
154
+ criterion: "testableSuccessCriteria",
155
+ label: "Success criteria are concretely testable",
156
+ met: success.trim().length > 0 &&
157
+ /\b(?:done when|pass(?:es)?|fails?|asserts?|verif(?:y|ied)|observable|expected result|acceptance)\b/i.test(success) &&
158
+ /\b(?:test|command|step|case|assert|expect|check)\b/i.test(success),
159
+ detail: success.trim()
160
+ ? "success criteria section is concrete"
161
+ : "missing success criteria section",
162
+ },
163
+ ];
164
+ const metCount = results.reduce((n, r) => n + (r.met ? 1 : 0), 0);
165
+ const maxScore = results.length;
166
+ return {
167
+ results,
168
+ metCount,
169
+ maxScore,
170
+ ratio: maxScore > 0 ? metCount / maxScore : 0,
171
+ missing: results.filter((r) => !r.met).map((r) => r.label),
172
+ fileMap,
173
+ };
174
+ }
175
+ export function formatPlanDepthRubric(score) {
176
+ const header = `plan depth: ${score.metCount}/${score.maxScore} ` +
177
+ `(${pct.format(score.ratio * 100)}%)`;
178
+ const lines = score.results.map((r) => ` [${r.met ? "x" : " "}] ${r.label} — ${r.detail}`);
179
+ const tail = score.missing.length > 0 ? [` missing: ${score.missing.join(", ")}`] : [];
180
+ return [header, ...lines, ...tail].join("\n");
181
+ }
182
+ function withinScope(path, planned) {
183
+ if (path === planned)
184
+ return true;
185
+ const p = planned.replace(/\/+$/, "");
186
+ return path.startsWith(`${p}/`);
187
+ }
188
+ export function detectScopeDrift(planDoc, touchedFiles) {
189
+ const plannedFiles = extractPlanFileMap(planDoc);
190
+ const normalizedTouched = [
191
+ ...new Set(touchedFiles.map((p) => p.replace(/^\.\//, ""))),
192
+ ].sort();
193
+ if (plannedFiles.length === 0) {
194
+ return {
195
+ plannedFiles,
196
+ touchedFiles: normalizedTouched,
197
+ outOfScope: normalizedTouched,
198
+ };
199
+ }
200
+ return {
201
+ plannedFiles,
202
+ touchedFiles: normalizedTouched,
203
+ outOfScope: normalizedTouched.filter((t) => !plannedFiles.some((p) => withinScope(t, p))),
204
+ };
205
+ }
84
206
  /**
85
207
  * Score a spec/plan markdown document against {@link PLAN_CRITERIA}. Pure and
86
208
  * deterministic — pass the spec text, the plan text, or both concatenated. Each
@@ -1 +1 @@
1
- {"version":3,"file":"plan-rubric.js","sourceRoot":"","sources":["../src/plan-rubric.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"plan-rubric.js","sourceRoot":"","sources":["../src/plan-rubric.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import { type RunManifest, type StageRecord } from "./run-report.js";
2
+ export type ReviewSeveritySummary = {
3
+ blocker: number;
4
+ major: number;
5
+ minor: number;
6
+ nit: number;
7
+ suppressed: number;
8
+ };
9
+ export type ScopeDriftSummary = {
10
+ plannedFiles: string[];
11
+ touchedFiles: string[];
12
+ outOfScope: string[];
13
+ };
14
+ export type FinalizeReportContext = {
15
+ manifest: RunManifest;
16
+ stages: StageRecord[];
17
+ headSha?: string | null;
18
+ changedFiles?: string[];
19
+ scopeDrift?: ScopeDriftSummary | null;
20
+ };
21
+ export declare const DEFAULT_REPORT_LEGIBILITY_THRESHOLD = 1;
22
+ export declare function extractRunReport(stageResult: string): string | null;
23
+ export declare function summarizeReviewSeverity(stages: StageRecord[]): ReviewSeveritySummary | null;
24
+ export declare function buildFallbackRunReport(ctx: FinalizeReportContext): string;
25
+ export declare function finalizeReportText(reportText: string | null, ctx: FinalizeReportContext): string;
26
+ //# sourceMappingURL=report-finalize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report-finalize.d.ts","sourceRoot":"","sources":["../src/report-finalize.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,WAAW,EACjB,MAAM,iBAAiB,CAAC;AAKzB,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,QAAQ,EAAE,WAAW,CAAC;IACtB,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,UAAU,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;CACvC,CAAC;AAEF,eAAO,MAAM,mCAAmC,IAAI,CAAC;AAErD,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAInE;AAWD,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,WAAW,EAAE,GACpB,qBAAqB,GAAG,IAAI,CAmB9B;AAmJD,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,qBAAqB,GAAG,MAAM,CAkEzE;AAED,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,MAAM,GAAG,IAAI,EACzB,GAAG,EAAE,qBAAqB,GACzB,MAAM,CAUR"}