fix(segment): a table cell is not a sentence — split it, like a paragraph - #2
Merged
Conversation
CORE.LEN.01 begrenst een ZIN: "Een zin ZOU NIET langer MOETEN zijn dan de grens van
zijn artefactsoort." De segmenteerder hield zich daar niet aan voor tabellen. Elke cel
werd één unit, hoeveel proza er ook in stond, terwijl een alinea al sinds jaar en dag
eerst wordt verzameld en dan in zinnen gesplitst.
Waarom dat meer is dan een schoonheidsfoutje: het maakt de regel ONREPAREERBAAR. Een
veld-referentiecel met vijf zinnen werd gemeld als één zin van 85 woorden. De schrijver
volgt de reparatietekst ("splits de zin op het voegwoord"), splitst netjes op de punt,
en het getal beweegt niet — want de cel blijft één unit. Wat overblijft zijn twee
slechte uitwegen: snijden tot voorbij de betekenis, of de baseline ophogen. Allebei zijn
in de praktijk gebruikt.
## De wijziging
Een cel wordt nu behandeld als een alinea: verzamelen, maskeren, splitsen. Twee dingen
veranderen BEWUST niet.
- De unit-soort blijft `line`. Een cel is geen vrijstaande zin in een alinea, en de
vormregels leunen op dat onderscheid.
- Alle zinnen van één cel houden hetzelfde block-id, dus een regel met `unit: 'block'`
ziet nog steeds de hele cel — `groupByLine()` groepeert op block-id, niet op regel.
Alleen de GRENZEN verschuiven. `maskInline` is lengte-behoudend, dus een offset in de
gemaskeerde cel is dezelfde offset in de ruwe cel en dus in de bronkolom.
## Gemeten op een echt corpus, niet op een voorbeeld
39 spec-bestanden van het Studio Groei-platform:
| | errors | warns | zinnen | dichtheid |
|------------|--------|-------|--------|-----------|
| cel = 1 zin | 23 | 387 | 9978 | 38.79 |
| cel gesplitst | 23 | 368 | 10301 | 35.72 |
Belangrijker dan het saldo is de samenstelling: **31 warns verdwenen en 12 kwamen erbij.**
De 31 waren cellen die alleen te lang waren omdat er meer zinnen in stonden. De 12 zijn
échte zinnen boven de 30 woorden die eerst wegvielen doordat hun cel al als één eenheid
was geteld. De meting wordt dus in twee richtingen scherper, niet alleen milder. Errors
bleven op 23: geen enkel document gaat hierdoor van conformerend naar falend.
## Versie: MINOR
Het criterium uit deel 5 is "kan een document dat gisteren conformeerde, vandaag falen?"
Nee — conformiteit hangt aan errors, en die bewegen niet. Maar PATCH dekt het evenmin:
dat vraagt "wijzigingen in het gereedschap die het oordeel niet veranderen", en het
oordeel verandert wel degelijk. Een poort die op wárn-aantallen ratelt kan hierdoor
eenmalig verspringen. Vandaar 0.2.0 → 0.3.0, en niet stiller.
## Tests
Vier nieuwe tests in `segment.test.js`, mutatie-getoetst: met alleen de productiecode
teruggedraaid zakt de suite van 41/41 naar 37/41 — alle vier vallen om. Ze dekken het
splitsen zelf, het gedeelde block-id, de kolom-offset per zin, en een cel met inline
code (die valt om zodra `maskInline` ooit niet meer lengte-behoudend is).
`npm test` 41/41 · `npm run conformance` 248/248 over 30 regels · `npm run lint:self`
exit 0, 0 errors.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changes
CORE.LEN.01measures a sentence. The segmenter did not honour that inside tables: everytable cell became one unit, however much prose it held, while a paragraph has always been
collected first and only then split into sentences. A cell is now treated like a paragraph.
No rule file changed. This is a segmentation fix in
tools/klaar/src/segment.js.Why
The old behaviour did not just over-count — it made the rule unfixable.
A field-reference cell carrying five sentences was reported as one sentence of 85 words. The
author follows the rule's own fix text ("split the sentence at the conjunction"), splits neatly
at the full stop, and the number does not move, because the cell is still one unit. The only
remaining options are cutting past the point of meaning, or raising the baseline.
Both were taken in anger. In the Studio Groei platform the KLAAR baseline was raised six times
in six days (304 → 312 → 362 → 366 → 379 → 387 warns), and the
waaromon the last bump saysso itself: "TWEEDE ophoging in dezelfde sessie... dit is een gewoonte die je niet moet laten
sluipen." Meanwhile 7 of the last 8 red CI runs on that repo were this ratchet.
A gate whose fix text does not work is worse than no gate: it teaches people to edit the
baseline instead of the text.
Evidence
Measured on a real corpus — the 39 spec documents of the Studio Groei platform, not an invented
example.
The net figure is the least interesting part. The composition matters:
sentences.
because their cell had already been counted once as a single unit.
So the measurement gets sharper in both directions, not merely gentler. Errors stayed at 23:
no document moves from conforming to failing.
Real example of a newly visible one, from
docs/architecture/data-layer.md:And a representative disappearing one, from the table that triggered this work — a cell holding
five sentences of telemetry documentation, reported as a single 85-word sentence.
What deliberately does not change
line. A cell is not a free-standing sentence in a paragraph, and theshape rules lean on that distinction.
unit: 'block'stillsees the whole cell —
groupByLine()groups on block id, not on line.Only the boundaries move.
maskInlineis length-preserving, so an offset into the masked cell isthe same offset into the raw cell, and therefore into the source column.
Version: MINOR (0.2.0 → 0.3.0)
Part 5 asks: can a document that conformed yesterday fail today? No — conformance hangs on
errors, and those do not move. But PATCH does not cover it either: PATCH is for "tool changes
that do not change the verdict", and the verdict does change. A gate that ratchets on warning
counts can shift once because of this. Hence MINOR rather than something quieter.
Checks
node tools/klaar/bin/klaar.js checkpassesnode tools/klaar/bin/klaar.js conformancepasses — 248 passed, 0 failed, over 30 rulescd tools/klaar && node --test test/passes — 41/41npm run lint:selfexit 0, 0 errorsMutation-tested, not assumed. With only the production file reverted and the new tests kept,
the suite drops from 41/41 to 37/41 — all four new tests fail. They cover the split itself,
the shared block id, the per-sentence column offset, and a cell containing inline code (which
fails the moment
maskInlinestops preserving length).Clean-room declaration
from ASD-STE100 or from any other licence-restricted specification.
sourcefrom the allowlist in CLEANROOM.md.(No lexicon terms were added.)