parseRequirements: colon-aligned separators and unbounded Traceability section create phantom requirements (false /cad-audit FAIL) #41

Closed
opened 2026-07-23 14:32:02 +00:00 by crenshawdev · 0 comments
crenshawdev commented 2026-07-23 14:32:02 +00:00 (Migrated from github.com)

Severity: medium · Area: audit · surfaced in the post-v1.2.0 cross-model review sweep. Two independent trip-wires in one parser; the colon case was reproduced with a fixture.

parseRequirements (cadence-core/bin/lib/planning-files.mjs:82-95) feeds /cad-audit, the pre-ship traceability gate. Two soft spots each mint a phantom requirement row, which surfaces as a broken/no-phase requirement and flips the audit to a false FAIL on an otherwise clean project.

1. Colon-aligned table separators are not skipped

planning-files.mjs:90: if (!id || id === 'Requirement' || /^-+$/.test(id)) continue;

The separator-row skip matches only all-dash cells. Markdown alignment separators contain colons (|:------------|:-----:|-------:|), so the first cell :------------ fails /^-+$/ and is not skipped — it becomes a requirement literally named :------------ with no phase. The shipped template uses plain dashes, but any hand-edit or regeneration of the table can introduce alignment colons, after which the ship gate fails for no real reason.

2. The Traceability section is unbounded

planning-files.mjs:83: const section = text.split(/^## Traceability\s*$/m)[1];

This captures everything after the ## Traceability heading to end-of-file, with no stop at the next ## heading. Today Traceability is the last section, so it is latent — but the moment any table-bearing section is added after it, those rows parse as requirements too.

Fix direction

  • Tolerate alignment colons in the separator skip (e.g. treat a row whose cells are only -, :, and spaces as a separator).
  • Bound the section to the next top-level heading: split off everything from ## Traceability up to the next ^## .

One fix pass hardens both; both protect the same gate (/cad-audit).

**Severity:** medium · **Area:** audit · surfaced in the post-v1.2.0 cross-model review sweep. Two independent trip-wires in one parser; the colon case was reproduced with a fixture. `parseRequirements` (`cadence-core/bin/lib/planning-files.mjs:82-95`) feeds `/cad-audit`, the pre-ship traceability gate. Two soft spots each mint a phantom requirement row, which surfaces as a broken/no-phase requirement and flips the audit to a false FAIL on an otherwise clean project. ## 1. Colon-aligned table separators are not skipped `planning-files.mjs:90`: `if (!id || id === 'Requirement' || /^-+$/.test(id)) continue;` The separator-row skip matches only all-dash cells. Markdown alignment separators contain colons (`|:------------|:-----:|-------:|`), so the first cell `:------------` fails `/^-+$/` and is not skipped — it becomes a requirement literally named `:------------` with no phase. The shipped template uses plain dashes, but any hand-edit or regeneration of the table can introduce alignment colons, after which the ship gate fails for no real reason. ## 2. The Traceability section is unbounded `planning-files.mjs:83`: `const section = text.split(/^## Traceability\s*$/m)[1];` This captures everything after the `## Traceability` heading to end-of-file, with no stop at the next `## ` heading. Today Traceability is the last section, so it is latent — but the moment any table-bearing section is added after it, those rows parse as requirements too. ## Fix direction - Tolerate alignment colons in the separator skip (e.g. treat a row whose cells are only `-`, `:`, and spaces as a separator). - Bound the section to the next top-level heading: split off everything from `## Traceability` up to the next `^## `. One fix pass hardens both; both protect the same gate (`/cad-audit`).
Sign in to join this conversation.
No description provided.