Summary
extractRequirementsSection (src/core/parsers/requirement-blocks.ts) splits the ## Requirements section into blocks by scanning line-by-line for ### Requirement: headers (REQUIREMENT_HEADER_PREFIX). The scan is not fence-aware: a ### Requirement: line inside a fenced code block (a documentation example) is treated as a real requirement header. This cuts the block mid-fence, promotes the fenced example into a phantom requirement, and emits a dangling ``` in any rebuilt output (e.g. on archive).
Language-agnostic — reproduces with English-only specs.
Reproduction
A ## Requirements section whose body contains a fenced example that itself shows a ### Requirement: line:
## Requirements
### Requirement: Real
The system SHALL do the real thing.
Example of how to author a requirement:
```markdown
### Requirement: Example
The system SHALL be an example only.
```
#### Scenario: ok
- **WHEN** x
- **THEN** y
Parsing yields two requirements (Real and the fenced Example) instead of one, and the code fence is broken across the split. On archive, the rebuilt spec contains a phantom ### Requirement: Example and an unbalanced fence.
Expected
A ### Requirement: inside a fenced code block is documentation, not a requirement, and should be ignored by the block splitter — exactly as #### Scenario: inside a fence is handled by the scenario parser.
Root cause
Both the preamble scan and the per-block boundary scan test REQUIREMENT_HEADER_PREFIX with no fence mask:
// preamble
while (cursor < body.length && !REQUIREMENT_HEADER_PREFIX.test(body[cursor])) { ... }
// per-block boundary
while (cursor < body.length && !REQUIREMENT_HEADER_PREFIX.test(body[cursor]) && !/^##\s+/.test(body[cursor])) { ... }
Suggested fix
Build a code-fence mask over the section body once (the codebase already has a buildCodeFenceMask helper used by the scenario parser) and gate the header test on !fenceMask[i], mirroring the fence-aware handling already applied to #### Scenario: parsing.
Found while hardening a downstream fork; reproduces on upstream with English-only specs, so filing here rather than carrying a fork-local patch.
Summary
extractRequirementsSection(src/core/parsers/requirement-blocks.ts) splits the## Requirementssection into blocks by scanning line-by-line for### Requirement:headers (REQUIREMENT_HEADER_PREFIX). The scan is not fence-aware: a### Requirement:line inside a fenced code block (a documentation example) is treated as a real requirement header. This cuts the block mid-fence, promotes the fenced example into a phantom requirement, and emits a dangling``` in any rebuilt output (e.g. onarchive).Language-agnostic — reproduces with English-only specs.
Reproduction
A
## Requirementssection whose body contains a fenced example that itself shows a### Requirement:line:Parsing yields two requirements (
Realand the fencedExample) instead of one, and the code fence is broken across the split. Onarchive, the rebuilt spec contains a phantom### Requirement: Exampleand an unbalanced fence.Expected
A
### Requirement:inside a fenced code block is documentation, not a requirement, and should be ignored by the block splitter — exactly as#### Scenario:inside a fence is handled by the scenario parser.Root cause
Both the preamble scan and the per-block boundary scan test
REQUIREMENT_HEADER_PREFIXwith no fence mask:Suggested fix
Build a code-fence mask over the section body once (the codebase already has a
buildCodeFenceMaskhelper used by the scenario parser) and gate the header test on!fenceMask[i], mirroring the fence-aware handling already applied to#### Scenario:parsing.Found while hardening a downstream fork; reproduces on upstream with English-only specs, so filing here rather than carrying a fork-local patch.