Split out of #338, which delivered the site-voice gate. This is a known gap in the detector that gate depends on, recorded rather than left to be rediscovered.
The gap
_sloplib.find_prose_separator_dashes is line-based: _segment_separates requires word characters on both sides of the dash on the same line. A separator dash that lands at a line-wrap boundary is therefore invisible:
...it holds in one of three states —
listed below.
find_prose_separator_dashes scores that 0.
How it surfaced
While fixing #338's 118 flagged lines, three such dashes were found by hand in site/src/content/docs/codearbiter-directory.md — real VOICE.md violations a reader sees, that the gate did not report. They were fixed, but the gate would not catch a new one, and a contributor who wraps a line can pass it without meaning to.
Why it was not fixed there
Closing it needs paragraph-level analysis (join soft-wrapped lines before scanning, while still reporting the original line number, and without joining across list items, table rows, headings, or fence boundaries). That is a different shape of change from the per-line scan, and #338 was already extending the scope predicate, adding the definition-list exemption, rewriting 15 pages, and wiring a new CI gate.
Acceptance criteria
- AC-1: a separator dash at a line-wrap boundary is reported, with the line number of the dash.
- AC-2: joining does not create false positives across a list-item boundary, a table row, a heading, or a fenced-code boundary.
- AC-3: the existing exemptions still hold after joining — inline code, URLs, numeric/date ranges, and the definition-list lead-in.
- AC-4: the three real cases from
codearbiter-directory.md (recoverable from this PR's diff) are pinned as fixtures.
- AC-5:
check_site_voice.py's "KNOWN GAP" docstring section is removed when this lands.
Relevant sources
core/pysrc/_sloplib.py — find_prose_separator_dashes, _segment_separates, _prose_only
.github/scripts/check_site_voice.py — the gate, and the docstring recording this gap
plugins/ca/hooks/tests/test_sloplib.py — where the fixtures belong
Split out of #338, which delivered the site-voice gate. This is a known gap in the detector that gate depends on, recorded rather than left to be rediscovered.
The gap
_sloplib.find_prose_separator_dashesis line-based:_segment_separatesrequires word characters on both sides of the dash on the same line. A separator dash that lands at a line-wrap boundary is therefore invisible:find_prose_separator_dashesscores that 0.How it surfaced
While fixing #338's 118 flagged lines, three such dashes were found by hand in
site/src/content/docs/codearbiter-directory.md— real VOICE.md violations a reader sees, that the gate did not report. They were fixed, but the gate would not catch a new one, and a contributor who wraps a line can pass it without meaning to.Why it was not fixed there
Closing it needs paragraph-level analysis (join soft-wrapped lines before scanning, while still reporting the original line number, and without joining across list items, table rows, headings, or fence boundaries). That is a different shape of change from the per-line scan, and #338 was already extending the scope predicate, adding the definition-list exemption, rewriting 15 pages, and wiring a new CI gate.
Acceptance criteria
codearbiter-directory.md(recoverable from this PR's diff) are pinned as fixtures.check_site_voice.py's "KNOWN GAP" docstring section is removed when this lands.Relevant sources
core/pysrc/_sloplib.py—find_prose_separator_dashes,_segment_separates,_prose_only.github/scripts/check_site_voice.py— the gate, and the docstring recording this gapplugins/ca/hooks/tests/test_sloplib.py— where the fixtures belong