fix: seat a category by its kind, not by its name

improvise-cj4u (P2). View::on_category_added took a name and asked
CategoryKind::of_name, which reads Label as Regular by design.
Workbook::add_label_category papered over that with a set_axis(None)
straight afterwards, so views existing at that moment were right;
Workbook::create_view had only names to hand and had no such correction,
so every view created after a label pivoted it onto Row — and on an
already-pivoted document onto Page, filtering the whole document down to
one description.

on_category_added now takes the CategoryKind, and the two set_axis
corrections are deleted: one answer to "where does this category go"
rather than two, of which only one caller knew to write the second. The
signature change is deliberate — it is what made the compiler name every
call site. Every site outside Workbook is test code and passes
of_name(name), which preserves what those fixtures meant.

Shares a theme with improvise-dy3j — a Label kind that cannot cross a
boundary carrying only a name — but not a mechanism: dy3j is the file
format, this is a function signature. Fixed separately for that reason.

The control tests carry as much as the fix: a blanket `unseated = true`
satisfies every label assertion in the repository, so the direction the
bug cannot supply is asserted too, and a label is shown not to consume
the Row slot the next regular category wants. Reasoning in
context/code/core.md §9; evidence in context/test-evidence/core.md.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
This commit is contained in:
Edward Langley
2026-09-22 00:57:48 -07:00
parent d9f732c529
commit c80da1be36
6 changed files with 145 additions and 36 deletions
+43
View File
@@ -1143,3 +1143,46 @@ luck. It is the same shape as `analyze_records`' five-iteration guard.
This one cannot be made to fail by re-introducing a `HashMap` *reliably*, which
is why the test that carries the load is its sibling above; kept because the
repetition is what documents that hash order was the defect.
### a_view_created_after_a_label_still_keeps_it_off_the_axes
`View::on_category_added` took a name and asked `CategoryKind::of_name`, which
reads `Label` as `Regular` by design. `Workbook::add_label_category` papered
over that by calling `set_axis(name, Axis::None)` straight afterwards, so the
views existing *at that moment* were right; `Workbook::create_view` had only
names to hand and had no such correction, so every view created after the label
pivoted it. Reproduced at `d46ec59`: `Description` on `Axis::Row` in a view
created one line after `add_label_category`.
The fix gives seating the kind, and the two `set_axis` corrections are deleted —
one answer rather than two, of which only one caller knew to write the second.
### a_view_created_after_a_regular_category_still_seats_it_on_row
The control, and the direction the bug's own shape cannot supply. Seating
everything on `Axis::None` satisfies the label assertion above completely, so
without this a blanket `unseated = true` reads as a fix.
Fault injected: `let unseated = true;`. This test fails (`left: None right:
Row`) along with `a_label_does_not_displace_a_regular_category_in_a_new_view`
and `first_category_goes_to_row_second_to_column_rest_to_page`, while every
label assertion in the repository still passes.
### a_label_does_not_displace_a_regular_category_in_a_new_view
The consequence the per-category assertions cannot state, because seating is
**order-dependent**: the first regular category takes Row, the second Column,
the rest Page. A label wrongly counted as regular therefore does not merely sit
in the wrong place — it *consumes the slot* the next real category wanted, and
on an already-pivoted document it pushes that category to `Page`, which
filters the whole document down to one value.
The fixture adds the label first and the regular category second, so the
displacement is what is measured rather than the label's own axis.
Fault injected: restoring `let unseated = CategoryKind::of_name(cat_name)
.is_virtual() || self.is_records_layout();`. Five tests fail, including the two
pre-existing ones (`add_label_category_sets_none_axis_on_all_views`,
`label_category_defaults_to_none_axis`) that used to be carried by the deleted
`set_axis` correction — which is the evidence that the consolidation did not
cost coverage.