refactor(axis): consolidate axis presentation onto the Axis enum

Axis label and color tables were spread across four sites: the tile bar,
the category panel, the view panel, and the tile command. Adding an axis
variant meant finding all four. They now hang off Axis in view/axis.rs.

The ticket's signature was a layering violation. It asked for
display_short() -> (&'static str, Color), but Color is a ratatui type and
Axis lives in improvise-core, which may not name a UI type. Split into
color() -> AxisColor, a semantic palette, plus the label methods, with
draw.rs::axis_fg resolving the palette to a terminal color -- the same
arrangement minibuf_fg already has for MinibufColor.

The ticket also called the category panel an "exact copy" of the tile
bar. It was not. The colors were identical; the labels were not ("Row ↕"
vs "Row", "None ∅" vs "·"). So only the color table was true
duplication, and that is the part with nothing keeping the two copies in
agreement. The four label sets are four deliberate vocabularies and stay
four methods -- plain_label, glyph (Display appends it), short_label
(three columns; None is "·", not a truncation of "Non"), and initial
(one letter; None is empty). A characterization test pins all four
verbatim so the move could not quietly restyle anything.

next() replaces the rotation match in both cmd/tile.rs and
View::cycle_axis. is_data_axis() from the ticket is omitted: no caller
wanted it.

Not touched: persistence/mod.rs maps Axis to the on-disk keywords. That
is a format concern and belongs in the io layer.

Closes improvise-rml

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V69PGQfMJuGRmtSWpfVAqn
This commit is contained in:
Edward Langley
2026-08-31 22:30:16 -07:00
parent 5430bded86
commit c9b256889d
10 changed files with 161 additions and 55 deletions
+13
View File
@@ -450,3 +450,16 @@ work_done('improvise-8uz',refactor,'View lost selected/row_offset/col_offset; Vi
decision('improvise-8uz',exemption_deleted,'the view_only_effects_leave_shared_state_alone exemption for SetSelected/SetRowOffset/SetColOffset is deleted: they no longer touch anything shared, so every ViewOnly effect now clears the same bar with no special cases. That exemption was the ticket''s original symptom.').
doctrine(check_the_ticket_premise,'a ticket that states a fact about the system as the basis for its options is stating a hypothesis; test it before choosing among the options, because a false premise usually invalidates the option set rather than one option').
doctrine(characterization_survives_the_move,'for a relocation refactor, write the behaviour test against the OLD location first and carry it across unchanged in meaning; if it needs new assertions to pass, the relocation changed behaviour').
% ---------------------------------------------------------------------------
% improvise-rml: axis presentation consolidated onto the Axis enum.
% ---------------------------------------------------------------------------
location(axis_presentation,'crates/improvise-core/src/view/axis.rs','plain_label/glyph/short_label/initial/color/next on Axis; AxisColor semantic palette').
location(axis_color_resolution,'src/draw.rs','axis_fg maps AxisColor to a ratatui Color, beside minibuf_fg which does the same for MinibufColor').
invariant(semantic_palette_at_the_core_boundary,'a core type that needs a color names a semantic enum, never a ratatui Color; the rendering layer owns the one mapping. Precedents: MinibufColor -> minibuf_fg, AxisColor -> axis_fg. This is what forbidden(improvise_core,ui) requires in practice.').
kb_issue_found(ticket_premise_false_rml,'improvise-rml called category_panel.rs an "exact copy" of tile_bar.rs. It was not: the colors were identical but the labels differed ("Row ↕" vs "Row", "None ∅" vs "·"). Only the color table was true duplication; the four label sets are four deliberate vocabularies and were preserved as four methods.').
decision('improvise-rml',semantic_color_not_ratatui,'the ticket specified display_short() -> (&''static str, Color). Color is a ratatui type and Axis lives in improvise-core, so that signature is the layering violation forbidden(improvise_core,ui) names. Split into color() -> AxisColor plus short_label(), with draw.rs::axis_fg resolving the palette.').
decision('improvise-rml',is_data_axis_omitted,'the ticket also asked for is_data_axis() -> bool. No caller wanted it, so it was left out rather than added speculatively.').
work_done('improvise-rml',refactor,'Axis gained next/color/plain_label/glyph/short_label/initial; Display is now plain_label+glyph. Four duplicate match sites replaced: tile_bar, category_panel, view_panel, cmd/tile.rs. View::cycle_axis now calls Axis::next. Characterization test pins all four label vocabularies verbatim.').
work_unblocked('improvise-rml','improvise-dz8','adding Axis::Filter now means filling in one file rather than finding four scattered exhaustive matches').