cf2e66b39ee3dfed910258eccfa886ae2e02feaf
2 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
b205e4c2b2 |
fix(#1639): parseDecisions handles the titled-colon bullet form (#1665)
* fix(#1639): parseDecisions handles titled-colon bullet form bulletColonRe anchors on ':**' (colon immediately before close-bold) and bulletEmDashRe requires an em-dash, so the titled-colon form '- **D-NN: Title.** body' (title between the colon and the closing **) matched neither and was dropped by the parse-miss guard. When all decisions used the titled convention, parseDecisions returned 0 and check.decision-coverage- plan passed vacuously — the same false-coverage failure mode as #1343/#1364/#1365. Add a third per-form regex bulletTitledColonRe, checked LAST (strict superset of bulletColonRe, so it only catches bullets the other two miss — minimal blast radius); id + [tags] trackability honored. Regression folded into decisions.test.cjs: titled-colon parses, coexists with colon/em-dash, tags, all-titled-13 no longer vacuously 0. * fix(#1639): tighten titled-colon title to [^:*]* so malformed pre-colon-run bullets still reject The first cut's title run [^*]* was too permissive: it matched a genuinely-malformed bullet with a colon in the pre-separator freeform run (e.g. 'D-07 ratio 3:1:**') by treating the 3:1 colon as the separator, regressing the #1343 parse-miss guard tests. Tighten the title to [^:*]* (no colon, no star) so the separator colon remains the only colon permitted before ** — matching bulletColonRe's existing [^:*]* discipline. Valid titled forms (colon-free titles) still parse; the malformed colon-in-freeform case still falls through to the parse-miss guard. * chore(#1639): backfill changeset pr ref to 1665 |
||
|
|
e58b5e1721 |
fix(#1364): decisions adopt markdown-sectionizer seam + fail-loud coverage gate (epic #1372 T1) (#1386)
* test(#1364,#1365): add decisions regression tests (fail-first proof) Adds tests/decisions.test.cjs with: - #1364 recall tests: parseDecisions from markdown-header + em-dash bullets (these FAIL on pre-T1 code, proving the bug is present before the fix) - #1365 fail-loud tests: check.decision-coverage-plan must return passed:false for decision-shaped but 0-extracted content (FAIL pre-T1, gate silently passed) - extractDecisions outcome enum tests (could-not-parse/none-present/parsed) - Parser QA matrix: CRLF, unicode headings, fenced-code suppression, both bullet forms - Boundary/threshold tests at limit-1 (0), limit (1) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#1364,#1365): adopt markdown-sectionizer seam in decisions.cts; add fail-loud gate #1364 — Recall: decisions.cts now uses the seam's extractTaggedBlocks and collectSection for the markdown-header fallback path. Em-dash bullet form (- **D-NN — title** body) is now recognised alongside the existing colon form. #1365 — Fail-loud: adds extractDecisions() returning a typed DecisionExtraction { decisions, outcome } where outcome is 'parsed' | 'none-present' | 'could-not-parse'. The blocking gate (cmdDecisionCoveragePlan) now treats could-not-parse as passed:false with a format-mismatch reason instead of the prior silent passed:true/skip. gap-checker runGapAnalysis surfaces 'extracted 0 of N — possible format mismatch' for could-not-parse instead of 'No requirements or decisions to check'. parseDecisions remains a thin delegate over extractDecisions, so all existing callers are unaffected. Seam adoption: stripFencedCode (seam), extractTaggedBlocks(content,'decisions') (seam), collectSection(content, /decisions?/i, {levelBounded,stripFences}) (seam). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#1364,#1365): tighten could-not-parse, parse-miss fail-loud, curly-quote discretion, gap-checker FIX D FIX A: empty <decisions> scaffolds and all-prose sections no longer return could-not-parse; outcome is none-present unless the block/section contains a \bD- token or a parse-miss, preventing false blocks on legitimate phases. FIX B: parseDecisionLines now tracks parse-misses (D-NN-shaped bullets that fail both regexes); extractDecisions returns could-not-parse when parseMisses>0 even if some decisions parsed — silent drops no longer mask format errors. FIX C: curly-quote normalization regex now includes actual U+2018/U+2019 characters so '### Claude's Discretion' (curly apostrophe) correctly yields trackable:false (regression vs pre-T1 behavior). FIX D: gap-checker runGapAnalysis surfaces the decision could-not-parse format-mismatch signal independently of whether requirements items exist — previously masked inside `if (items.length === 0)`. Adds 14 behavioral regression tests (fail-first verified manually before fixes). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#1365): fail-loud gate on parse-miss regardless of covered decisions Change the `could-not-parse` guard in `cmdDecisionCoveragePlan` and `cmdDecisionCoverageVerify` from `decisions.length === 0 && outcome === 'could-not-parse'` to fire on `outcome === 'could-not-parse'` alone. Previously a CONTEXT.md with a valid D-01 (covered by the plan) plus a malformed D-02 (parse-miss) would skip the guard (length === 1), proceed to coverage, find D-01 covered, and silently return passed:true — hiding the D-02 parse-miss entirely. Adds a gate-level fail-first test that places D-01 into a ## Must Haves section (DESIGNATED_HEADINGS_RE match) so coverage of D-01 would pass on its own, proving the only path to passed:false is the parse-miss fix. Also adds the matching verify-side advisory assertion. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore(#1364,#1365): add Fixed changeset (pr:0 placeholder) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore(#1364): backfill changeset PR number (1386) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |