@dzhechkov/harness-core 0.8.36 → 0.8.38

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 (112) hide show
  1. package/.dz-manifest.json +216 -76
  2. package/README.md +349 -8
  3. package/dist/agentdb-index.d.ts +87 -7
  4. package/dist/agentdb-index.d.ts.map +1 -1
  5. package/dist/agentdb-index.js +416 -57
  6. package/dist/agentdb-index.js.map +1 -1
  7. package/dist/apply-leg.d.ts +19 -1
  8. package/dist/apply-leg.d.ts.map +1 -1
  9. package/dist/apply-leg.js +187 -36
  10. package/dist/apply-leg.js.map +1 -1
  11. package/dist/codex-rollouts.d.ts +118 -0
  12. package/dist/codex-rollouts.d.ts.map +1 -0
  13. package/dist/codex-rollouts.js +297 -0
  14. package/dist/codex-rollouts.js.map +1 -0
  15. package/dist/cost-ledger.d.ts +56 -4
  16. package/dist/cost-ledger.d.ts.map +1 -1
  17. package/dist/cost-ledger.js +176 -20
  18. package/dist/cost-ledger.js.map +1 -1
  19. package/dist/cross-family-control.d.ts +380 -0
  20. package/dist/cross-family-control.d.ts.map +1 -0
  21. package/dist/cross-family-control.js +848 -0
  22. package/dist/cross-family-control.js.map +1 -0
  23. package/dist/debt-ratchet.d.ts +53 -0
  24. package/dist/debt-ratchet.d.ts.map +1 -0
  25. package/dist/debt-ratchet.js +107 -0
  26. package/dist/debt-ratchet.js.map +1 -0
  27. package/dist/embedding-config.d.ts +42 -0
  28. package/dist/embedding-config.d.ts.map +1 -1
  29. package/dist/embedding-config.js +106 -10
  30. package/dist/embedding-config.js.map +1 -1
  31. package/dist/feature-adr-checkpoints.d.ts +6 -0
  32. package/dist/feature-adr-checkpoints.d.ts.map +1 -1
  33. package/dist/feature-adr-checkpoints.js +29 -0
  34. package/dist/feature-adr-checkpoints.js.map +1 -1
  35. package/dist/feature-adr-decision-recall.d.ts +2 -2
  36. package/dist/feature-adr-decision-recall.d.ts.map +1 -1
  37. package/dist/feature-adr-decision-recall.js +5 -3
  38. package/dist/feature-adr-decision-recall.js.map +1 -1
  39. package/dist/feature-adr-envelope.d.ts +96 -0
  40. package/dist/feature-adr-envelope.d.ts.map +1 -0
  41. package/dist/feature-adr-envelope.js +183 -0
  42. package/dist/feature-adr-envelope.js.map +1 -0
  43. package/dist/feature-adr-routing.d.ts +64 -0
  44. package/dist/feature-adr-routing.d.ts.map +1 -1
  45. package/dist/feature-adr-routing.js +133 -3
  46. package/dist/feature-adr-routing.js.map +1 -1
  47. package/dist/feature-adr-stage-canon.d.ts +79 -0
  48. package/dist/feature-adr-stage-canon.d.ts.map +1 -0
  49. package/dist/feature-adr-stage-canon.js +117 -0
  50. package/dist/feature-adr-stage-canon.js.map +1 -0
  51. package/dist/index.d.ts +21 -9
  52. package/dist/index.d.ts.map +1 -1
  53. package/dist/index.js +15 -5
  54. package/dist/index.js.map +1 -1
  55. package/dist/loop-blobs.generated.js +4 -4
  56. package/dist/loop-blobs.generated.js.map +1 -1
  57. package/dist/mutation-gate.d.ts +51 -0
  58. package/dist/mutation-gate.d.ts.map +1 -1
  59. package/dist/mutation-gate.js +295 -0
  60. package/dist/mutation-gate.js.map +1 -1
  61. package/dist/qe-bridge.d.ts +8 -0
  62. package/dist/qe-bridge.d.ts.map +1 -1
  63. package/dist/qe-bridge.js +4 -2
  64. package/dist/qe-bridge.js.map +1 -1
  65. package/dist/qe-findings.d.ts +107 -0
  66. package/dist/qe-findings.d.ts.map +1 -0
  67. package/dist/qe-findings.js +417 -0
  68. package/dist/qe-findings.js.map +1 -0
  69. package/dist/recap.d.ts +1 -1
  70. package/dist/recap.d.ts.map +1 -1
  71. package/dist/recap.js +4 -2
  72. package/dist/recap.js.map +1 -1
  73. package/dist/review-cost.d.ts +51 -0
  74. package/dist/review-cost.d.ts.map +1 -0
  75. package/dist/review-cost.js +110 -0
  76. package/dist/review-cost.js.map +1 -0
  77. package/dist/round.d.ts +207 -1
  78. package/dist/round.d.ts.map +1 -1
  79. package/dist/round.js +321 -4
  80. package/dist/round.js.map +1 -1
  81. package/dist/run-records.d.ts +97 -0
  82. package/dist/run-records.d.ts.map +1 -1
  83. package/dist/run-records.js +336 -2
  84. package/dist/run-records.js.map +1 -1
  85. package/dist/score.d.ts +44 -1
  86. package/dist/score.d.ts.map +1 -1
  87. package/dist/score.js +78 -5
  88. package/dist/score.js.map +1 -1
  89. package/package.json +1 -1
  90. package/sbom.json +425 -75
  91. package/src/agentdb-index.ts +423 -60
  92. package/src/apply-leg.ts +187 -36
  93. package/src/codex-rollouts.ts +374 -0
  94. package/src/cost-ledger.ts +232 -24
  95. package/src/cross-family-control.ts +1038 -0
  96. package/src/debt-ratchet.ts +143 -0
  97. package/src/embedding-config.ts +131 -10
  98. package/src/feature-adr-checkpoints.ts +29 -0
  99. package/src/feature-adr-decision-recall.ts +6 -4
  100. package/src/feature-adr-envelope.ts +242 -0
  101. package/src/feature-adr-routing.ts +150 -3
  102. package/src/feature-adr-stage-canon.ts +141 -0
  103. package/src/index.ts +65 -6
  104. package/src/loop-blobs.generated.ts +4 -4
  105. package/src/mutation-gate.ts +316 -0
  106. package/src/qe-bridge.ts +12 -2
  107. package/src/qe-findings.ts +463 -0
  108. package/src/recap.ts +10 -3
  109. package/src/review-cost.ts +139 -0
  110. package/src/round.ts +481 -6
  111. package/src/run-records.ts +388 -2
  112. package/src/score.ts +115 -6
@@ -0,0 +1,107 @@
1
+ /**
2
+ * qe-findings-record (ADR-001, tier M): machine-readable Step-8 verdict + findings ledger.
3
+ *
4
+ * Two prior facts drove this (Step 0, `00_complexity_assessment.md`): scoring reads review PROSE
5
+ * with a regex (`readQeGrade` in score.ts) and 41 of 100 feature reports came back `ambiguous`
6
+ * because a report that was fixed after review states two grades in prose — a real fact about the
7
+ * report, not a parser bug. Findings were not read at all: `dz score` could say "cross-model QE ran"
8
+ * but never how many BLOCKER/HIGH findings it raised or what happened to them.
9
+ *
10
+ * This module adds ONE machine-readable surface on top of the prose, never replacing it:
11
+ * - `QE-VERDICT: <A|A-|A+|B|B+|B-|C|C+|C-|D>` — a single line, the source of truth when present.
12
+ * - a `Findings ledger` table under the EXACT header `QE_FINDINGS_HEADER`, closed dictionaries for
13
+ * Severity/Status/Author. A row outside the dictionary is REFUSED, never coerced to the nearest
14
+ * known value (ADR-001 D2) — that would make the resulting severity/status tally unprovable.
15
+ * - an empty (header-only) table is `hollow: true` — worse than no table at all (ADR-001 D3, the
16
+ * same principle as the mutation table's `present-unproven` in score.ts).
17
+ *
18
+ * Absence of either surface is NOT an error: 406 pre-existing reports carry neither, and this module
19
+ * reports `{status:'absent'}` for them exactly as it always will (ADR-001 D4, NFR-1).
20
+ *
21
+ * fix-round-1 (codex-r1-verdict, Grade C, findings 1/2/5/6/7): a machine artifact recognised inside
22
+ * fenced/indented code, a blockquote or an HTML comment is not a machine artifact — a review that
23
+ * QUOTES the format as an example must not be read as the report's own verdict/table. Both scans
24
+ * below run over TEXT MASKED THE SAME WAY as `amendment-trace.ts` (`maskMarkdown`), plus one block
25
+ * kind that shared masker does not cover — blockquotes — added here as the minimal local pass the
26
+ * ADR calls for. Masking blanks a line to spaces of the SAME LENGTH, so every line number reported
27
+ * in `refused`/`QeVerdictInvalidLine` still points at the real line in the ORIGINAL text.
28
+ *
29
+ * The findings table is additionally accepted ONLY under the single, top-level `## Findings ledger`
30
+ * heading (finding 1); a table found anywhere else is refused `outside ledger section`, never parsed.
31
+ *
32
+ * PURE, deliberately: no node:fs import here (NFR-2, guarded by test/core-boundary.test.ts). File
33
+ * reads belong to the CLI / the calling agent, same as every other core module.
34
+ */
35
+ export declare const QE_SEVERITIES: readonly ["BLOCKER", "CRITICAL", "HIGH", "MEDIUM", "LOW", "INFO"];
36
+ export type QeSeverity = (typeof QE_SEVERITIES)[number];
37
+ export declare const QE_STATUSES: readonly ["confirmed", "fixed", "partial", "refuted", "named-limit", "open"];
38
+ export type QeStatus = (typeof QE_STATUSES)[number];
39
+ export declare const QE_AUTHORS: readonly ["codex", "claude", "lead"];
40
+ export type QeAuthor = (typeof QE_AUTHORS)[number];
41
+ /** The ONE exact heading a producer must write and a reader must find — see score.ts's own
42
+ * comment on why this is a single shared constant rather than two strings that can drift apart. */
43
+ export declare const QE_FINDINGS_HEADER = "| Finding | Severity | Status | Round | Author | Title |";
44
+ /** The section a Findings ledger table must live directly under — fix-round-1 finding 1: a table
45
+ * found anywhere else (before this heading, after the section ends, or with no/duplicate heading)
46
+ * is `refused` as `outside ledger section`, never parsed as the real ledger. */
47
+ export declare const QE_LEDGER_HEADING = "## Findings ledger";
48
+ /** `QE-VERDICT: B`, `QE-VERDICT: A-`, `QE-VERDICT: A+` — a whole line, nothing trailing but
49
+ * whitespace. Only A-D (FR-1); this is deliberately narrower than score.ts's prose GRADE_RE, which
50
+ * also accepts E/F and looser punctuation because prose is written by hand. */
51
+ export declare const QE_VERDICT_RE: RegExp;
52
+ /** Every `QE-VERDICT:` line found, normalised, IN DOCUMENT ORDER (duplicates included — the caller
53
+ * decides whether repeats of the SAME grade still count as ambiguous; ADR-001 D1 says they do:
54
+ * "две строки — ambiguous, никогда «последняя побеждает»"). Scans MASKED text (fix-round-1 finding
55
+ * 1): a `QE-VERDICT:` line inside a fenced/indented code block, a blockquote or an HTML comment is
56
+ * an EXAMPLE, not the report's own verdict, and must never be counted. */
57
+ export declare function readQeVerdictLines(md: string): string[];
58
+ export interface QeVerdictInvalidLine {
59
+ /** 1-based line number in the ORIGINAL (unmasked) text. */
60
+ readonly line: number;
61
+ /** The raw line text, exactly as written (from the original, unmasked text). */
62
+ readonly text: string;
63
+ }
64
+ /**
65
+ * fix-round-1 finding 2: lines that LOOK LIKE a `QE-VERDICT:` declaration (any case, any leading
66
+ * whitespace, with or without the colon) but do not match the strict grammar — `QE-VERDICT: B – final`
67
+ * (en dash + trailing prose), wrong case, a missing colon, a grade outside A-D. Masked the same way as
68
+ * `readQeVerdictLines` — a malformed EXAMPLE inside a fence/quote/comment is still not a real attempt.
69
+ * A genuinely valid line is never reported here (it belongs to `readQeVerdictLines` instead).
70
+ */
71
+ export declare function findInvalidQeVerdictLines(md: string): readonly QeVerdictInvalidLine[];
72
+ export interface QeFindingRow {
73
+ readonly finding: string;
74
+ readonly severity: QeSeverity;
75
+ readonly status: QeStatus;
76
+ readonly round: number;
77
+ readonly author: QeAuthor;
78
+ readonly title: string;
79
+ }
80
+ export interface QeFindingsRefusedRow {
81
+ /** 1-based line number in the source text the refused row (or duplicate/misplaced table header)
82
+ * starts at. */
83
+ readonly line: number;
84
+ /** The raw line text, exactly as written. */
85
+ readonly text: string;
86
+ /** Why the row (or table) was refused — human-readable, not a code. */
87
+ readonly reason: string;
88
+ }
89
+ export interface QeFindingsSummary {
90
+ readonly bySeverity: Readonly<Record<string, number>>;
91
+ readonly byStatus: Readonly<Record<string, number>>;
92
+ readonly total: number;
93
+ }
94
+ export type QeFindingsResult = {
95
+ readonly status: 'absent';
96
+ } | {
97
+ readonly status: 'present';
98
+ /** Header-only table (no data rows at all, valid or refused) — worse than no table (D3). */
99
+ readonly hollow: boolean;
100
+ /** accepted | accepted-hollow (header only) | rejected-only (every table was refused) — lead delta after Codex r2 */
101
+ readonly tableStatus: 'accepted' | 'accepted-hollow' | 'rejected-only';
102
+ readonly rows: readonly QeFindingRow[];
103
+ readonly refused: readonly QeFindingsRefusedRow[];
104
+ readonly summary: QeFindingsSummary;
105
+ };
106
+ export declare function parseQeFindings(md: string): QeFindingsResult;
107
+ //# sourceMappingURL=qe-findings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qe-findings.d.ts","sourceRoot":"","sources":["../src/qe-findings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAIH,eAAO,MAAM,aAAa,mEAAoE,CAAC;AAC/F,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAExD,eAAO,MAAM,WAAW,8EAA+E,CAAC;AACxG,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAEpD,eAAO,MAAM,UAAU,sCAAuC,CAAC;AAC/D,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;AAEnD;oGACoG;AACpG,eAAO,MAAM,kBAAkB,6DAA6D,CAAC;AAE7F;;iFAEiF;AACjF,eAAO,MAAM,iBAAiB,uBAAuB,CAAC;AAEtD;;gFAEgF;AAChF,eAAO,MAAM,aAAa,QAAsC,CAAC;AAyFjE;;;;2EAI2E;AAC3E,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,CAQvD;AAED,MAAM,WAAW,oBAAoB;IACnC,2DAA2D;IAC3D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,gFAAgF;IAChF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,oBAAoB,EAAE,CAarF;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,oBAAoB;IACnC;qBACiB;IACjB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,6CAA6C;IAC7C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,uEAAuE;IACvE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACtD,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACpD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,MAAM,gBAAgB,GACxB;IAAE,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAA;CAAE,GAC7B;IACE,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,4FAA4F;IAC5F,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,qHAAqH;IACrH,QAAQ,CAAC,WAAW,EAAE,UAAU,GAAG,iBAAiB,GAAG,eAAe,CAAC;IACvE,QAAQ,CAAC,IAAI,EAAE,SAAS,YAAY,EAAE,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,SAAS,oBAAoB,EAAE,CAAC;IAClD,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;CACrC,CAAC;AAuFN,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,gBAAgB,CAoJ5D"}
@@ -0,0 +1,417 @@
1
+ /**
2
+ * qe-findings-record (ADR-001, tier M): machine-readable Step-8 verdict + findings ledger.
3
+ *
4
+ * Two prior facts drove this (Step 0, `00_complexity_assessment.md`): scoring reads review PROSE
5
+ * with a regex (`readQeGrade` in score.ts) and 41 of 100 feature reports came back `ambiguous`
6
+ * because a report that was fixed after review states two grades in prose — a real fact about the
7
+ * report, not a parser bug. Findings were not read at all: `dz score` could say "cross-model QE ran"
8
+ * but never how many BLOCKER/HIGH findings it raised or what happened to them.
9
+ *
10
+ * This module adds ONE machine-readable surface on top of the prose, never replacing it:
11
+ * - `QE-VERDICT: <A|A-|A+|B|B+|B-|C|C+|C-|D>` — a single line, the source of truth when present.
12
+ * - a `Findings ledger` table under the EXACT header `QE_FINDINGS_HEADER`, closed dictionaries for
13
+ * Severity/Status/Author. A row outside the dictionary is REFUSED, never coerced to the nearest
14
+ * known value (ADR-001 D2) — that would make the resulting severity/status tally unprovable.
15
+ * - an empty (header-only) table is `hollow: true` — worse than no table at all (ADR-001 D3, the
16
+ * same principle as the mutation table's `present-unproven` in score.ts).
17
+ *
18
+ * Absence of either surface is NOT an error: 406 pre-existing reports carry neither, and this module
19
+ * reports `{status:'absent'}` for them exactly as it always will (ADR-001 D4, NFR-1).
20
+ *
21
+ * fix-round-1 (codex-r1-verdict, Grade C, findings 1/2/5/6/7): a machine artifact recognised inside
22
+ * fenced/indented code, a blockquote or an HTML comment is not a machine artifact — a review that
23
+ * QUOTES the format as an example must not be read as the report's own verdict/table. Both scans
24
+ * below run over TEXT MASKED THE SAME WAY as `amendment-trace.ts` (`maskMarkdown`), plus one block
25
+ * kind that shared masker does not cover — blockquotes — added here as the minimal local pass the
26
+ * ADR calls for. Masking blanks a line to spaces of the SAME LENGTH, so every line number reported
27
+ * in `refused`/`QeVerdictInvalidLine` still points at the real line in the ORIGINAL text.
28
+ *
29
+ * The findings table is additionally accepted ONLY under the single, top-level `## Findings ledger`
30
+ * heading (finding 1); a table found anywhere else is refused `outside ledger section`, never parsed.
31
+ *
32
+ * PURE, deliberately: no node:fs import here (NFR-2, guarded by test/core-boundary.test.ts). File
33
+ * reads belong to the CLI / the calling agent, same as every other core module.
34
+ */
35
+ import { maskMarkdown } from './markdown-masker.js';
36
+ export const QE_SEVERITIES = ['BLOCKER', 'CRITICAL', 'HIGH', 'MEDIUM', 'LOW', 'INFO'];
37
+ export const QE_STATUSES = ['confirmed', 'fixed', 'partial', 'refuted', 'named-limit', 'open'];
38
+ export const QE_AUTHORS = ['codex', 'claude', 'lead'];
39
+ /** The ONE exact heading a producer must write and a reader must find — see score.ts's own
40
+ * comment on why this is a single shared constant rather than two strings that can drift apart. */
41
+ export const QE_FINDINGS_HEADER = '| Finding | Severity | Status | Round | Author | Title |';
42
+ /** The section a Findings ledger table must live directly under — fix-round-1 finding 1: a table
43
+ * found anywhere else (before this heading, after the section ends, or with no/duplicate heading)
44
+ * is `refused` as `outside ledger section`, never parsed as the real ledger. */
45
+ export const QE_LEDGER_HEADING = '## Findings ledger';
46
+ /** `QE-VERDICT: B`, `QE-VERDICT: A-`, `QE-VERDICT: A+` — a whole line, nothing trailing but
47
+ * whitespace. Only A-D (FR-1); this is deliberately narrower than score.ts's prose GRADE_RE, which
48
+ * also accepts E/F and looser punctuation because prose is written by hand. */
49
+ export const QE_VERDICT_RE = /^QE-VERDICT:\s*([A-D][+−-]?)\s*$/m;
50
+ /** Any line that OPENS a verdict declaration — any case, any leading whitespace, with or without the
51
+ * colon — checked separately from `QE_VERDICT_RE`'s strict grammar (fix-round-1 finding 2): this is
52
+ * what lets `readQeGrade` tell "no verdict was ever attempted" (legacy prose fallback allowed) apart
53
+ * from "a verdict was attempted and is malformed" (fallback forbidden — the report must say `invalid`
54
+ * rather than silently reading a stale prose grade). */
55
+ const QE_VERDICT_LOOKALIKE_RE = /^\s*QE-VERDICT\b/i;
56
+ /** U+2212 (minus sign) and the ASCII hyphen spell the same grade sign — the same normalisation
57
+ * score.ts's `normaliseGradeSign` applies to prose grades, duplicated here (not imported) so this
58
+ * module never depends on score.ts and stays the leaf of the dependency graph. */
59
+ function normaliseVerdictSign(grade) {
60
+ return grade.replace('−', '-');
61
+ }
62
+ /** A leading Markdown blockquote marker (CommonMark: up to 3 leading spaces, then `>`).
63
+ * `maskMarkdown` (the canonical shared masker, also used by amendment-trace.ts) does not mask
64
+ * blockquotes — only fences, indented code and HTML comments — so this ONE missing block kind is
65
+ * added here as the minimal local pass fix-round-1 calls for, with the same blank-to-spaces
66
+ * contract (line count and every other line's length never change). */
67
+ const BLOCKQUOTE_RE = /^ {0,3}>/;
68
+ /** CommonMark block starters that INTERRUPT a paragraph (so they can never be a lazy continuation
69
+ * of a blockquote): ATX heading, thematic break, fenced code, table row, list item, HTML block. */
70
+ const BLOCK_STARTER_RE = /^ {0,3}(?:#{1,6}(?:\s|$)|(?:[-*_])(?: *[-*_]){2,} *$|```|~~~|\||(?:[-*+]|\d{1,9}[.)])\s|<)/;
71
+ /**
72
+ * qe-findings-lazy-blockquote (backlog baba20e3b1c14060): a `>` line only opens the mask — a
73
+ * CommonMark blockquote paragraph can continue onto a FOLLOWING line that carries no `>` marker at
74
+ * all (a "lazy continuation"), and that unmarked line still belongs to the quote. The original
75
+ * single-line `.map()` masked only lines that themselves started with `>`, so a `QE-VERDICT: X` or
76
+ * `## Findings ledger` line written as the *second* line of a quoted example (no blank line, no
77
+ * `>`) was left unmasked and misread as the report's own artifact.
78
+ *
79
+ * Fix: a small two-state line machine (in-quote / not-in-quote). Once a `>` line is seen, every
80
+ * following line is ALSO masked until the first blank line (a line with no non-whitespace
81
+ * character) or end-of-input — the blank line is the ONLY terminator (a deliberate
82
+ * over-approximation of strict CommonMark, which also lets a block-starting line such as an ATX
83
+ * heading end a paragraph early: `01_requirements.md` FR-4 / acid A2 require the opposite, that a
84
+ * `## Findings ledger` heading glued to a quote with no blank separation stays masked, so the
85
+ * ambiguous case is read fail-closed as "still inside the quote" rather than as a real heading).
86
+ * A line already blanked by an earlier pass (fence/indented-code/HTML-comment) has no
87
+ * non-whitespace character either, so it is read as blank and CLOSES an open run rather than
88
+ * extending it — the existing already-masked invariant (line 90-93 above) holds unchanged.
89
+ */
90
+ function maskBlockquotes(md) {
91
+ let inQuote = false;
92
+ return md
93
+ .split('\n')
94
+ .map((line) => {
95
+ if (BLOCKQUOTE_RE.test(line)) {
96
+ inQuote = true;
97
+ return ' '.repeat(line.length);
98
+ }
99
+ if (!inQuote)
100
+ return line;
101
+ if (!/\S/.test(line)) {
102
+ inQuote = false; // FR-2: a blank line always ends the lazy-continuation run
103
+ return line;
104
+ }
105
+ if (BLOCK_STARTER_RE.test(line)) {
106
+ // FR-1 clause (b), lead delta after Step 8 (F1/F2): a line that STARTS A NEW BLOCK — ATX
107
+ // heading, thematic break, fence, table row, list item, HTML block — interrupts the quoted
108
+ // paragraph per CommonMark, so it is NOT a lazy continuation: it and everything after it
109
+ // are outside the quote. Without this, a real `## Findings ledger` heading or a real table
110
+ // glued under a `> note` line vanished into a SILENT `absent` — exactly the near-miss-vs-
111
+ // absent failure this module exists to prevent.
112
+ inQuote = false;
113
+ return line;
114
+ }
115
+ return ' '.repeat(line.length); // FR-1: lazy continuation — still inside the quote
116
+ })
117
+ .join('\n');
118
+ }
119
+ /** The one masking pass both scans below share: fenced code, 4-space indented code and HTML
120
+ * comments (the canonical masker) plus blockquotes (the local addition above). Blockquote masking
121
+ * runs SECOND on purpose — a `>` line already blanked by the canonical pass (inside a fence) is all
122
+ * spaces and can never spuriously match `BLOCKQUOTE_RE` again; a live blockquote outside any fence
123
+ * is exactly what still needs masking. */
124
+ /** Lead delta after Codex r2 (#1 PARTIAL): HTML `<blockquote>…</blockquote>` regions are masked too
125
+ * (same-length blanking, newlines kept) — a quoted example inside them must not count. */
126
+ function maskHtmlBlockquotes(md) {
127
+ return md.replace(/<blockquote\b[\s\S]*?<\/blockquote>/gi, (m) => m.replace(/[^\n]/g, ' '));
128
+ }
129
+ function maskForScan(md) {
130
+ return maskBlockquotes(maskHtmlBlockquotes(maskMarkdown(md, { indentedCode: true, inlineComments: true })));
131
+ }
132
+ /** Every `QE-VERDICT:` line found, normalised, IN DOCUMENT ORDER (duplicates included — the caller
133
+ * decides whether repeats of the SAME grade still count as ambiguous; ADR-001 D1 says they do:
134
+ * "две строки — ambiguous, никогда «последняя побеждает»"). Scans MASKED text (fix-round-1 finding
135
+ * 1): a `QE-VERDICT:` line inside a fenced/indented code block, a blockquote or an HTML comment is
136
+ * an EXAMPLE, not the report's own verdict, and must never be counted. */
137
+ export function readQeVerdictLines(md) {
138
+ const found = [];
139
+ const masked = maskForScan(md);
140
+ const re = new RegExp(QE_VERDICT_RE.source, QE_VERDICT_RE.flags.includes('m') ? 'gm' : 'g');
141
+ for (const m of masked.matchAll(re)) {
142
+ found.push(normaliseVerdictSign(m[1]));
143
+ }
144
+ return found;
145
+ }
146
+ /**
147
+ * fix-round-1 finding 2: lines that LOOK LIKE a `QE-VERDICT:` declaration (any case, any leading
148
+ * whitespace, with or without the colon) but do not match the strict grammar — `QE-VERDICT: B – final`
149
+ * (en dash + trailing prose), wrong case, a missing colon, a grade outside A-D. Masked the same way as
150
+ * `readQeVerdictLines` — a malformed EXAMPLE inside a fence/quote/comment is still not a real attempt.
151
+ * A genuinely valid line is never reported here (it belongs to `readQeVerdictLines` instead).
152
+ */
153
+ export function findInvalidQeVerdictLines(md) {
154
+ const masked = maskForScan(md);
155
+ const maskedLines = masked.split('\n');
156
+ const originalLines = md.split('\n');
157
+ const strict = new RegExp(QE_VERDICT_RE.source);
158
+ const out = [];
159
+ for (let i = 0; i < maskedLines.length; i++) {
160
+ const line = maskedLines[i];
161
+ if (!QE_VERDICT_LOOKALIKE_RE.test(line))
162
+ continue;
163
+ if (strict.test(line))
164
+ continue; // grammatically valid — readQeVerdictLines already has it
165
+ out.push({ line: i + 1, text: originalLines[i] });
166
+ }
167
+ return out;
168
+ }
169
+ const SEVERITY_SET = new Set(QE_SEVERITIES);
170
+ const STATUS_SET = new Set(QE_STATUSES);
171
+ const AUTHOR_SET = new Set(QE_AUTHORS);
172
+ /** A markdown table separator row, e.g. `|---|---|---|---|---|---|` or `| --- | :--- | ---: |`. */
173
+ const SEPARATOR_RE = /^\|[\s:|-]+\|$/;
174
+ /** A top-level Markdown heading (`#` through `######`, ATX-style) — used to close a `## Findings
175
+ * ledger` section at the next heading of any level, same as a reader would read the document. */
176
+ const TOP_LEVEL_HEADING_RE = /^#{1,6}\s/;
177
+ /** Splits the INSIDE of a `| a | b | c |` row on top-level `|` boundaries: a `\|` is a literal pipe
178
+ * (never a boundary — fix-round-1 finding 5), and a `|` inside a single-backtick inline-code span is
179
+ * never a boundary either (`` `a|b` `` stays one cell). Deliberately minimal — not a full CommonMark
180
+ * table parser; nested/nested-backtick edge cases are out of scope. */
181
+ function splitTableCells(inner) {
182
+ const cells = [];
183
+ let current = '';
184
+ let inCode = false;
185
+ let codeFence = 0;
186
+ for (let i = 0; i < inner.length; i++) {
187
+ const ch = inner[i];
188
+ if (ch === '\\' && inner[i + 1] === '|') {
189
+ current += '|';
190
+ i++;
191
+ continue;
192
+ }
193
+ if (ch === '`') {
194
+ // Lead delta after Codex r2 (#5 PARTIAL): a code span opens with N backticks and closes only
195
+ // with a run of the SAME length — ``a|b`` must not flip twice on its double backticks.
196
+ let run = 0;
197
+ while (inner[i + run] === '`')
198
+ run++;
199
+ if (!inCode) {
200
+ inCode = true;
201
+ codeFence = run;
202
+ }
203
+ else if (run === codeFence) {
204
+ inCode = false;
205
+ codeFence = 0;
206
+ }
207
+ current += '`'.repeat(run);
208
+ i += run - 1;
209
+ continue;
210
+ }
211
+ if (ch === '|' && !inCode) {
212
+ cells.push(current.trim());
213
+ current = '';
214
+ continue;
215
+ }
216
+ current += ch;
217
+ }
218
+ cells.push(current.trim());
219
+ return cells;
220
+ }
221
+ /** Splits `| a | b | c |` into `['a', 'b', 'c']`, trimmed. Returns null when the line does not open
222
+ * and close with a pipe (not a table row at all) or has the wrong column count for this table. */
223
+ function splitRow(line, expectedCols) {
224
+ const t = line.trim();
225
+ if (!t.startsWith('|') || !t.endsWith('|'))
226
+ return null;
227
+ const cells = splitTableCells(t.slice(1, -1));
228
+ if (cells.length !== expectedCols)
229
+ return null;
230
+ return cells;
231
+ }
232
+ function parseRound(raw) {
233
+ if (!/^[0-9]+$/.test(raw))
234
+ return null;
235
+ const n = Number(raw);
236
+ return n >= 1 ? n : null;
237
+ }
238
+ /** Walks a table's body from just below its header (same rules as the real parse loop: an optional
239
+ * separator row, then rows starting with `|` until a blank line, a new header, or a non-table line)
240
+ * and counts how many row lines it contains — WITHOUT validating a single cell. Used only to make a
241
+ * refusal (duplicate or misplaced table) NAME how much was ignored (fix-round-1 finding 6), never to
242
+ * parse the rejected table's content. */
243
+ function countIgnoredRows(lines, headerIdx) {
244
+ let cursor = headerIdx + 1;
245
+ if (cursor < lines.length && SEPARATOR_RE.test(lines[cursor].trim()))
246
+ cursor++;
247
+ let count = 0;
248
+ while (cursor < lines.length) {
249
+ const trimmed = lines[cursor].trim();
250
+ if (trimmed === '')
251
+ break;
252
+ if (trimmed === QE_FINDINGS_HEADER)
253
+ break;
254
+ if (!trimmed.startsWith('|'))
255
+ break;
256
+ count++;
257
+ cursor++;
258
+ }
259
+ return count;
260
+ }
261
+ export function parseQeFindings(md) {
262
+ const lines = md.split('\n');
263
+ const maskedLines = maskForScan(md).split('\n');
264
+ // fix-round-1 finding 1: locate the single top-level `## Findings ledger` heading (masked-aware —
265
+ // a heading quoted inside a fence/blockquote/comment does not count). Zero or more-than-one such
266
+ // headings means there is NO section a table can be "under", and every table found is refused.
267
+ const headingIdxs = [];
268
+ for (let i = 0; i < maskedLines.length; i++) {
269
+ if (maskedLines[i].trim() === QE_LEDGER_HEADING)
270
+ headingIdxs.push(i);
271
+ }
272
+ let sectionStart = -1;
273
+ let sectionEnd = -1;
274
+ if (headingIdxs.length === 1) {
275
+ sectionStart = headingIdxs[0] + 1;
276
+ sectionEnd = maskedLines.length;
277
+ for (let i = sectionStart; i < maskedLines.length; i++) {
278
+ if (TOP_LEVEL_HEADING_RE.test(maskedLines[i])) {
279
+ sectionEnd = i;
280
+ break;
281
+ }
282
+ }
283
+ }
284
+ const inSection = (idx) => sectionStart >= 0 && idx >= sectionStart && idx < sectionEnd;
285
+ const noSectionReason = headingIdxs.length === 0
286
+ ? `no '${QE_LEDGER_HEADING}' heading in the report`
287
+ : headingIdxs.length > 1
288
+ ? `${headingIdxs.length} '${QE_LEDGER_HEADING}' headings found — the heading must be unique`
289
+ : '';
290
+ // Header-row detection is ALSO masked-aware (finding 1): a `QE_FINDINGS_HEADER` line inside a
291
+ // fence/indented block/blockquote/HTML comment is example text, never even a candidate.
292
+ const headerIdxs = [];
293
+ for (let i = 0; i < maskedLines.length; i++) {
294
+ if (maskedLines[i].trim() === QE_FINDINGS_HEADER)
295
+ headerIdxs.push(i);
296
+ }
297
+ if (headerIdxs.length === 0) {
298
+ // Lead delta (dogfooding the lead's own 08, 2026-09-17 02:08 UTC): a pipe-table sitting DIRECTLY
299
+ // under the single ledger heading whose header row is NOT the canonical one used to parse as
300
+ // `absent` — indistinguishable from "no ledger at all". It is a table the author MEANT as the
301
+ // ledger, so it is refused LOUDLY with the expected header spelled out (`rejected-only`).
302
+ if (sectionStart >= 0) {
303
+ for (let i = sectionStart; i < sectionEnd; i++) {
304
+ const t = maskedLines[i].trim();
305
+ if (t === '')
306
+ continue;
307
+ if (t.startsWith('|')) {
308
+ return {
309
+ status: 'present',
310
+ hollow: false,
311
+ tableStatus: 'rejected-only',
312
+ rows: [],
313
+ refused: [{ line: i + 1, text: lines[i], reason: `non-canonical header row: expected exactly '${QE_FINDINGS_HEADER}'` }],
314
+ summary: { bySeverity: {}, byStatus: {}, total: 0 },
315
+ };
316
+ }
317
+ break;
318
+ }
319
+ }
320
+ return { status: 'absent' };
321
+ }
322
+ const rows = [];
323
+ const refused = [];
324
+ let sawAnyRowLine = false;
325
+ let acceptedOne = false;
326
+ // Lead delta after Codex r2 (#1 PARTIAL): the table must sit DIRECTLY under the heading — only
327
+ // blank lines between `## Findings ledger` and the header row; prose in between disqualifies it.
328
+ const directlyUnderHeading = (idx) => {
329
+ if (sectionStart < 0 || idx < sectionStart)
330
+ return false;
331
+ for (let i = sectionStart; i < idx; i++)
332
+ if (maskedLines[i].trim() !== '')
333
+ return false;
334
+ return true;
335
+ };
336
+ for (const headerIdx of headerIdxs) {
337
+ const accept = !acceptedOne && inSection(headerIdx) && directlyUnderHeading(headerIdx);
338
+ if (!accept) {
339
+ const ignored = countIgnoredRows(lines, headerIdx);
340
+ const ignoredNote = ignored > 0 ? ` (${ignored} row(s) ignored)` : '';
341
+ const reason = inSection(headerIdx) && acceptedOne
342
+ ? `duplicate table: a Findings ledger table already appeared earlier in this report${ignoredNote}`
343
+ : inSection(headerIdx)
344
+ ? `not directly under the heading: prose sits between '${QE_LEDGER_HEADING}' and the table${ignoredNote}`
345
+ : `outside ledger section: ${noSectionReason || `must appear directly under the single '${QE_LEDGER_HEADING}' heading`}${ignoredNote}`;
346
+ refused.push({ line: headerIdx + 1, text: lines[headerIdx], reason });
347
+ continue;
348
+ }
349
+ acceptedOne = true;
350
+ let cursor = headerIdx + 1;
351
+ // Optional separator row right after the header.
352
+ if (cursor < lines.length && SEPARATOR_RE.test(lines[cursor].trim()))
353
+ cursor++;
354
+ while (cursor < lines.length) {
355
+ const raw = lines[cursor];
356
+ const trimmed = raw.trim();
357
+ if (trimmed === '')
358
+ break; // a blank line ends the table
359
+ if (trimmed === QE_FINDINGS_HEADER)
360
+ break; // a second header starts a NEW (duplicate) table
361
+ if (!trimmed.startsWith('|'))
362
+ break; // a non-table line ends the table
363
+ sawAnyRowLine = true;
364
+ const cells = splitRow(raw, 6);
365
+ if (cells === null) {
366
+ refused.push({ line: cursor + 1, text: raw, reason: 'malformed row: expected 6 columns' });
367
+ cursor++;
368
+ continue;
369
+ }
370
+ const [finding, severity, status, roundRaw, author, title] = cells;
371
+ const reasons = [];
372
+ if (finding === '' || /\s/.test(finding))
373
+ reasons.push(`Finding id ${JSON.stringify(finding)} must be a non-empty token with no whitespace`);
374
+ if (!SEVERITY_SET.has(severity))
375
+ reasons.push(`severity ${JSON.stringify(severity)} not in dictionary`);
376
+ if (!STATUS_SET.has(status))
377
+ reasons.push(`status ${JSON.stringify(status)} not in dictionary`);
378
+ const round = parseRound(roundRaw);
379
+ if (round === null)
380
+ reasons.push(`round ${JSON.stringify(roundRaw)} is not an integer >= 1`);
381
+ if (!AUTHOR_SET.has(author))
382
+ reasons.push(`author ${JSON.stringify(author)} not in dictionary`);
383
+ if (reasons.length > 0) {
384
+ refused.push({ line: cursor + 1, text: raw, reason: reasons.join('; ') });
385
+ }
386
+ else {
387
+ rows.push({
388
+ finding,
389
+ severity: severity,
390
+ status: status,
391
+ round: round,
392
+ author: author,
393
+ title,
394
+ });
395
+ }
396
+ cursor++;
397
+ }
398
+ }
399
+ const bySeverity = {};
400
+ const byStatus = {};
401
+ for (const r of rows) {
402
+ bySeverity[r.severity] = (bySeverity[r.severity] ?? 0) + 1;
403
+ byStatus[r.status] = (byStatus[r.status] ?? 0) + 1;
404
+ }
405
+ // Lead delta after Codex r2 (new MEDIUM #2): `hollow` means an ACCEPTED table with no rows — a
406
+ // report whose only tables were refused has no accepted table at all (`rejected-only`).
407
+ const tableStatus = !acceptedOne ? 'rejected-only' : (sawAnyRowLine ? 'accepted' : 'accepted-hollow');
408
+ return {
409
+ status: 'present',
410
+ hollow: tableStatus === 'accepted-hollow',
411
+ tableStatus,
412
+ rows,
413
+ refused,
414
+ summary: { bySeverity, byStatus, total: rows.length },
415
+ };
416
+ }
417
+ //# sourceMappingURL=qe-findings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qe-findings.js","sourceRoot":"","sources":["../src/qe-findings.ts"],"names":[],"mappings":"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"}
package/dist/recap.d.ts CHANGED
@@ -93,7 +93,7 @@ export type Delivery = {
93
93
  } | {
94
94
  readonly slug: string;
95
95
  readonly createdIso: string;
96
- readonly gradeStatus: 'ambiguous' | 'none' | 'no-report';
96
+ readonly gradeStatus: 'ambiguous' | 'invalid' | 'none' | 'no-report';
97
97
  readonly grade: null;
98
98
  };
99
99
  export interface Publish {
@@ -1 +1 @@
1
- {"version":3,"file":"recap.d.ts","sourceRoot":"","sources":["../src/recap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,uGAAuG;AACvG,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,CAAC;AAEpD,4FAA4F;AAC5F,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,WAAW,GAAG,MAAM,CAAC;AAE9D,eAAO,MAAM,gBAAgB,EAAE,SAAS,cAAc,EAAqC,CAAC;AAE5F,eAAO,MAAM,cAAc,EAAE,SAAS,YAAY,EAA6B,CAAC;AAKhF,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAC/B,sEAAsE;IACtE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,uDAAuD;IACvD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAqBD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,WAAW,CAc7E;AAED,uFAAuF;AACvF,wBAAgB,YAAY,CAAC,CAAC,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAUxE;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,QAAQ,CAAC;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,eAAe,CAqD7F;AAED,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,SAAS,GAAG,aAAa,CAAC;AAE/D,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,+FAA+F;IAC/F,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE;IAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,cAAc,CAwB1H;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,gFAAgF;IAChF,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;GAGG;AACH,eAAO,MAAM,iBAAiB,EAAE,SAAS,eAAe,EAOvD,CAAC;AAIF;;;;;;;;GAQG;AACH,MAAM,MAAM,QAAQ,GAChB;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC9G;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,WAAW,EAAE,WAAW,GAAG,MAAM,GAAG,WAAW,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAA;CAAE,CAAC;AAU3I,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,WAAW,CAAC,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,iFAAiF;IACjF,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,+FAA+F;IAC/F,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC;IAClD,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;IAChD,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC;IAC7C,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;IAClC,+FAA+F;IAC/F,QAAQ,CAAC,gBAAgB,EAAE,SAAS,MAAM,EAAE,CAAC;CAC9C;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,YAAY,GAAG,WAAW,GAAG,YAAY,GAAG,OAAO,CAAC;IACjE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;IACjC,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,SAAS,YAAY,EAAE,CAAC;IAC3C,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAiDD,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,WAAW,CAsGzD;AAQD,yGAAyG;AACzG,wBAAgB,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,EAAE,CAazD"}
1
+ {"version":3,"file":"recap.d.ts","sourceRoot":"","sources":["../src/recap.ts"],"names":[],"mappings":"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"}
package/dist/recap.js CHANGED
@@ -232,14 +232,16 @@ export function buildRecap(facts) {
232
232
  const covered = coveredWindow(v, facts.window);
233
233
  const items = (facts.deliveries?.items ?? []).map(normaliseDelivery).filter((d) => withinWindow(covered, d.createdIso));
234
234
  const graded = items.filter((d) => d.gradeStatus === 'unique');
235
- const ambiguous = items.filter((d) => d.gradeStatus === 'ambiguous');
235
+ // fix-round-1: 'invalid' (a malformed QE-VERDICT attempt) is folded into the same printed bucket
236
+ // as 'ambiguous' — both are "no single grade can be trusted", just a different reason.
237
+ const ambiguous = items.filter((d) => d.gradeStatus === 'ambiguous' || d.gradeStatus === 'invalid');
236
238
  const ungraded = items.filter((d) => d.gradeStatus === 'none' || d.gradeStatus === 'no-report');
237
239
  const lines = sectionLines(v, facts.window, (scope) => items.length === 0
238
240
  ? emptyOrUnavailable(v, `no feature directories were created in ${scope}`)
239
241
  : [
240
242
  `${items.length} feature director${items.length === 1 ? 'y' : 'ies'} created in ${scope}`,
241
243
  `${graded.length} carry a grade an independent review stated unambiguously${graded.length > 0 ? `: ${tally(graded.map((d) => d.grade))}` : ''}`,
242
- `${ambiguous.length} have a report that states MORE THAN ONE grade — reported as ambiguous, never guessed`,
244
+ `${ambiguous.length} have a report that states MORE THAN ONE grade or a malformed QE-VERDICT line — reported as ambiguous, never guessed`,
243
245
  `${ungraded.length} have no letter grade in their report, or no report at all`,
244
246
  'cadence is not value: this counts deliveries, not what they were worth',
245
247
  ]);