@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.
- package/.dz-manifest.json +216 -76
- package/README.md +349 -8
- package/dist/agentdb-index.d.ts +87 -7
- package/dist/agentdb-index.d.ts.map +1 -1
- package/dist/agentdb-index.js +416 -57
- package/dist/agentdb-index.js.map +1 -1
- package/dist/apply-leg.d.ts +19 -1
- package/dist/apply-leg.d.ts.map +1 -1
- package/dist/apply-leg.js +187 -36
- package/dist/apply-leg.js.map +1 -1
- package/dist/codex-rollouts.d.ts +118 -0
- package/dist/codex-rollouts.d.ts.map +1 -0
- package/dist/codex-rollouts.js +297 -0
- package/dist/codex-rollouts.js.map +1 -0
- package/dist/cost-ledger.d.ts +56 -4
- package/dist/cost-ledger.d.ts.map +1 -1
- package/dist/cost-ledger.js +176 -20
- package/dist/cost-ledger.js.map +1 -1
- package/dist/cross-family-control.d.ts +380 -0
- package/dist/cross-family-control.d.ts.map +1 -0
- package/dist/cross-family-control.js +848 -0
- package/dist/cross-family-control.js.map +1 -0
- package/dist/debt-ratchet.d.ts +53 -0
- package/dist/debt-ratchet.d.ts.map +1 -0
- package/dist/debt-ratchet.js +107 -0
- package/dist/debt-ratchet.js.map +1 -0
- package/dist/embedding-config.d.ts +42 -0
- package/dist/embedding-config.d.ts.map +1 -1
- package/dist/embedding-config.js +106 -10
- package/dist/embedding-config.js.map +1 -1
- package/dist/feature-adr-checkpoints.d.ts +6 -0
- package/dist/feature-adr-checkpoints.d.ts.map +1 -1
- package/dist/feature-adr-checkpoints.js +29 -0
- package/dist/feature-adr-checkpoints.js.map +1 -1
- package/dist/feature-adr-decision-recall.d.ts +2 -2
- package/dist/feature-adr-decision-recall.d.ts.map +1 -1
- package/dist/feature-adr-decision-recall.js +5 -3
- package/dist/feature-adr-decision-recall.js.map +1 -1
- package/dist/feature-adr-envelope.d.ts +96 -0
- package/dist/feature-adr-envelope.d.ts.map +1 -0
- package/dist/feature-adr-envelope.js +183 -0
- package/dist/feature-adr-envelope.js.map +1 -0
- package/dist/feature-adr-routing.d.ts +64 -0
- package/dist/feature-adr-routing.d.ts.map +1 -1
- package/dist/feature-adr-routing.js +133 -3
- package/dist/feature-adr-routing.js.map +1 -1
- package/dist/feature-adr-stage-canon.d.ts +79 -0
- package/dist/feature-adr-stage-canon.d.ts.map +1 -0
- package/dist/feature-adr-stage-canon.js +117 -0
- package/dist/feature-adr-stage-canon.js.map +1 -0
- package/dist/index.d.ts +21 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -5
- package/dist/index.js.map +1 -1
- package/dist/loop-blobs.generated.js +4 -4
- package/dist/loop-blobs.generated.js.map +1 -1
- package/dist/mutation-gate.d.ts +51 -0
- package/dist/mutation-gate.d.ts.map +1 -1
- package/dist/mutation-gate.js +295 -0
- package/dist/mutation-gate.js.map +1 -1
- package/dist/qe-bridge.d.ts +8 -0
- package/dist/qe-bridge.d.ts.map +1 -1
- package/dist/qe-bridge.js +4 -2
- package/dist/qe-bridge.js.map +1 -1
- package/dist/qe-findings.d.ts +107 -0
- package/dist/qe-findings.d.ts.map +1 -0
- package/dist/qe-findings.js +417 -0
- package/dist/qe-findings.js.map +1 -0
- package/dist/recap.d.ts +1 -1
- package/dist/recap.d.ts.map +1 -1
- package/dist/recap.js +4 -2
- package/dist/recap.js.map +1 -1
- package/dist/review-cost.d.ts +51 -0
- package/dist/review-cost.d.ts.map +1 -0
- package/dist/review-cost.js +110 -0
- package/dist/review-cost.js.map +1 -0
- package/dist/round.d.ts +207 -1
- package/dist/round.d.ts.map +1 -1
- package/dist/round.js +321 -4
- package/dist/round.js.map +1 -1
- package/dist/run-records.d.ts +97 -0
- package/dist/run-records.d.ts.map +1 -1
- package/dist/run-records.js +336 -2
- package/dist/run-records.js.map +1 -1
- package/dist/score.d.ts +44 -1
- package/dist/score.d.ts.map +1 -1
- package/dist/score.js +78 -5
- package/dist/score.js.map +1 -1
- package/package.json +1 -1
- package/sbom.json +425 -75
- package/src/agentdb-index.ts +423 -60
- package/src/apply-leg.ts +187 -36
- package/src/codex-rollouts.ts +374 -0
- package/src/cost-ledger.ts +232 -24
- package/src/cross-family-control.ts +1038 -0
- package/src/debt-ratchet.ts +143 -0
- package/src/embedding-config.ts +131 -10
- package/src/feature-adr-checkpoints.ts +29 -0
- package/src/feature-adr-decision-recall.ts +6 -4
- package/src/feature-adr-envelope.ts +242 -0
- package/src/feature-adr-routing.ts +150 -3
- package/src/feature-adr-stage-canon.ts +141 -0
- package/src/index.ts +65 -6
- package/src/loop-blobs.generated.ts +4 -4
- package/src/mutation-gate.ts +316 -0
- package/src/qe-bridge.ts +12 -2
- package/src/qe-findings.ts +463 -0
- package/src/recap.ts +10 -3
- package/src/review-cost.ts +139 -0
- package/src/round.ts +481 -6
- package/src/run-records.ts +388 -2
- 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 {
|
package/dist/recap.d.ts.map
CHANGED
|
@@ -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,
|
|
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,GAM9G;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,WAAW,EAAE,WAAW,GAAG,SAAS,GAAG,MAAM,GAAG,WAAW,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAA;CAAE,CAAC;AAUvJ,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,CAwGzD;AAQD,yGAAyG;AACzG,wBAAgB,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,EAAE,CAazD"}
|
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
|
-
|
|
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
|
]);
|