diff options
| author | Craig Jennings <c@cjennings.net> | 2026-07-29 06:26:11 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-07-29 06:26:11 -0500 |
| commit | ecd5d7b47d06c724086a1fa799fc984131493892 (patch) | |
| tree | f032a93ee7ce562406d14792c2695ad41180cd19 | |
| parent | 5999f88dd6e66794a9a0898ba643247de023ac2d (diff) | |
| download | rulesets-ecd5d7b47d06c724086a1fa799fc984131493892.tar.gz rulesets-ecd5d7b47d06c724086a1fa799fc984131493892.zip | |
docs: file the wrap-org-table row-splitting bug
wrap-org-table.el turns one logical table row into two, by writing a rule between its continuation lines. The predicate at wot--continuation-group-p requires every line past the first to carry an empty cell. A row that overflows every column has a fully-populated continuation, so the group is rejected and each physical line becomes its own row.
lint doesn't miss this. It causes it. lint-org.el:424 calls the same predicate, so it reports the tool's own correct output as missing rules between rows and names the tool as the fix. Follow that advice and the row splits, and lint then reports the result clean.
The fix is the round trip, not a detector. work implemented the predicate-based detection I recommended and showed it can't discriminate at any threshold: loose it condemns every table, tight it still mixes a wrapped row against two rows legitimately sharing a rule. Reflow twice and diff is true by construction and needs nobody to decide what a group means.
The task separates what I measured from what I inferred. The inference was refuted three times while the reproductions held, so the split is load-bearing rather than tidiness. Its review loop bounded out at three rounds. The open questions are what the reviewer and I could not settle between us.
work reported it. I hit the same failure on 2026-07-27 and left it in a session summary instead of filing it, which is why they met it three weeks later.
| -rw-r--r-- | todo.org | 44 |
1 files changed, 44 insertions, 0 deletions
@@ -58,6 +58,50 @@ Decisions settled with Craig, 2026-07-28, and shipped: Remaining: nothing on the design. The change shipped in this session. +** TODO [#B] wrap-org-table splits logical rows, and lint drives it :bug: +:PROPERTIES: +:LAST_REVIEWED: 2026-07-29 +:END: +Reported by work 2026-07-28 against =arch-00-deepsat-platform-spec-draft.org=. Reproduced here. + +*** Verified + +Each of these is a measurement, re-run under adversarial review. The analysis I built on top of them was wrong three times, so this section is deliberately separated from the open questions below. + +- *The defect.* =wrap-org-table.el= turns one logical table row into two or more, by writing a rule between its continuation lines. Content survives; structure does not. +- *Root cause.* =wot--continuation-group-p= (=wrap-org-table.el:168=) requires every line past the first to carry at least one empty cell. When a row overflows in every column its continuation line is fully populated, the predicate rejects the group, and =wot--logical-rows= appends each physical line as its own row (=:197=). +- *Controlled A/B.* Rules present in both, continuation line's middle cell the only variable: blank merges, populated splits. +- *Idempotence is broken.* Running the tool twice on its own correct output corrupts it. Pass 1 emits a properly rule-delimited three-line row; pass 2 splits it into three rows. The docstring at =:203-204= asserts the opposite, and =wot-reformat-is-idempotent= passes because its fixture overflows only one column. +- *lint doesn't just miss it, it causes it.* =lint-org.el:424= calls the same predicate. Given the tool's own correct output — a rule after every logical row — lint reports "missing rule between rows — wrap-org-table.el reflows it". Nothing is missing. Follow that advice and the tool splits the row; lint then reports the result 0 mechanical, 0 judgment. Control: a conformant table whose continuation keeps an empty cell returns 0 and 0. So the loop is not two independent green lights, it is the linter manufacturing a false violation and certifying the damage it caused. +- *A second path.* With no hlines at all, =wot--logical-rows= short-circuits (=:184=) before the predicate is reached, so every physical line becomes a row. +- *Nothing invokes the tool unattended.* =todo-cleanup.el= names it in comments only; the entry-script guard from the 2026-07-09 incident holds. +- *rulesets is exposed*: =todo.org= carries a four-row attachment-sanitization table with no rules between rows. Don't reflow it until the tool is fixed — reflowing is the trigger. + +*** Two fixes that were verified to work + +- *Conformant round-trip.* Replacing the predicate body with =(> (length group) 1)= — pure rule-delimited grouping, no emitter marker, no new field — makes the corrupting pass-1 output round-trip cleanly. +- *Telling a continuation group from two real rows at runtime.* Provenance isn't available (=wot-reformat-table-string= receives a string), but the test is cheap: merge the group, re-wrap at the allocated widths, compare to the group as given. A continuation group reproduces itself under merge-then-wrap; two genuinely distinct short rows don't, because merged they fit on one line. + +Start with a red test from the double-run repro — it needs no unusual input and falsifies the docstring and the passing idempotence test together. Emission is already correct (=:222-224= emits one rule per element of =rows=), so the repair is entirely in how =rows= is computed. + +*Prefer the round-trip check to any detector.* work implemented the predicate-based detection I recommended and demonstrated it cannot discriminate at any threshold (2026-07-29, worked examples from their repo). Run bare it flags 144 files — essentially every table — because an ordinary header-plus-body table is one multi-line fully-populated group and rejecting it is the predicate working correctly. Add a per-row-ruled precondition and it cuts to 9, but at 9 it still mixes a genuinely wrapped row (=arch-09:40=, a header row whose second line continues the sentence) with two distinct rows legitimately sharing a rule (their =todo.org:117=, where splitting is the *right* answer). Same structural signature, opposite correct verdicts. The difference is whether one line continues the other as prose, which is semantics and not in the parse. + +So =lint-org.el:424= cannot simply inherit the repair, and a checker keyed on the predicate would train people to ignore it. The idempotence property is the checkable one: reflow twice and diff. It sidesteps detection entirely, because round-tripping the tool's own output correctly is true by construction and needs nobody to decide what a group means. + +*** Open questions + +- *What should no-hline input do?* My "refuse to reflow" instruction was wrong: adding rules to a ruleless table is the tool's main job, and =test-wrap-org-table.el:147= asserts exactly that. The real danger is narrower — a no-hline table where some line carries an empty cell, so a physical line might be a continuation. Needs a decision on refuse, ask, or heuristic. +- *Which path bit work?* One question settles it: did the =arch-00= Document Status table have rules between its rows before the reflow? I inferred "probably secondary" from a file-level scan, which can't resolve a table-level incident. +- *How exposed is work?* Partly resolved by their own implementation, 2026-07-29. *Four secondary-path files are exact.* The primary-path number is 9 under a per-row-ruled precondition, which they correctly label a floor on a population they cannot cleanly define rather than a measurement — the precondition also drops the minimal =a_full= fixture, which has only two groups. My earlier "24 secondary-path files" certification was not sound: their original signature also matches every correctly-reflowed table, so it never partitioned. +- *Does the grade go up?* Currently Major x most users frequently = P2 = [#B] (any table you reflow that overflows every column, which is what a width violation sends you to the tool to fix). The lint-drives-it finding arrived after that grading and may lift it. + +*** Provenance + +work reverted their table and left it over-budget at 134 columns, correctly: an over-wide table is cosmetic, a table that says something else is not. I hit this same failure on 2026-07-27, wrote "reflowed a table into a worse shape and lint-org then passed it" into a session summary, and never filed it — which is why work met it three weeks later. Their framing beats the apology: a correct observation recorded and then read as fine is the same failure as a green check on a corrupted table. + +Process note for whoever picks this up. This task bounded out of its review loop at three rounds. Every finding across all three landed on inference, never on a measurement — the reproductions held throughout while the reasoning built on them was refuted repeatedly. Trust the Verified section; re-derive anything else. + + ** TODO [#B] Synced workflows link outside the synced set with ../../ :bug: :PROPERTIES: :LAST_REVIEWED: 2026-07-28 |
