docs: describe the derived cap and cite the coupling beads (improvise-felo.1)
Review of #307 at 7b9e868b: the duplicate-step evidence and argument still
said 12, tui.md bounded a collision tuple by twelve, and the coupling
inventory named no beads. The page-bar entry now notes its unclipped
set_string can overwrite the right border.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
This commit is contained in:
+14
-8
@@ -598,40 +598,46 @@ fixture that fills to the cap either derives it or fills until
|
||||
**Degrades as categories grow.** These are not fixed here; each is a place
|
||||
where 24 is worse than 12. Most were already reachable at 12.
|
||||
|
||||
- **The TUI row header is the sum of its levels.** In `src/ui/grid.rs`, around
|
||||
- **The TUI row header is the sum of its levels** (improvise-gtn7.5). In `src/ui/grid.rs`, around
|
||||
`row_header_width`/`data_area_width` (and
|
||||
`ui::viewport::compute_row_header_width`), each level takes 4 to 24 cells.
|
||||
Categories on Row therefore cost at least 4 cells each, and the data area
|
||||
saturates to zero width with no data drawn.
|
||||
- **Column headers take one line per level, but the keypress path does not
|
||||
count them.** `App`'s `visible_rows` is `term_height − 8`, a fixed allowance
|
||||
count them** (improvise-gtn7.6). `App`'s `visible_rows` is `term_height − 8`, a fixed allowance
|
||||
that ignores the column levels, the group row and the page bar. So with
|
||||
several categories on Column, the cursor can scroll below the drawn grid.
|
||||
- **The page bar is one unclipped line.** It is `GridWidget::render`'s
|
||||
`page_coords` join. Default seating (`View::on_category_added`) sends every
|
||||
- **The page bar is one unclipped line** (improvise-gtn7.7). It is
|
||||
`GridWidget::render`'s `page_coords` join, drawn with a bare `set_string`
|
||||
that is not clipped to the inner rectangle, so a long bar can overwrite the
|
||||
block's right border. Default seating (`View::on_category_added`) sends every
|
||||
regular category after the second to Page. A 24-category import therefore
|
||||
puts 22 selectors on one line, clips most of them without a mark, and opens
|
||||
on a single slice.
|
||||
- **Side panels do not scroll.** In `src/ui/panel.rs`, an item past
|
||||
- **Side panels do not scroll** (improvise-gtn7.8). In `src/ui/panel.rs`, an item past
|
||||
`item_height` is not drawn, and the cursor can move onto it unseen. The
|
||||
category panel lists every category plus its expanded items.
|
||||
- **The wizard's field list does not scroll.** Its `ReviewProposals` arm in
|
||||
- **The wizard's field list does not scroll** (improvise-8jk6.1). Its `ReviewProposals` arm in
|
||||
`src/ui/import_wizard_ui.rs` breaks at the popup's bottom (the popup is at
|
||||
most 30 rows high), unlike the steps that use `scrolling`. About 22 fields
|
||||
fit, so the over-the-cap case cannot show every field it asks the user to
|
||||
fix.
|
||||
- **Loading the store is O(k log k) per cell and O(cells × k) in memory.** It
|
||||
- **Loading the store is O(k log k) per cell and O(cells × k) in memory**
|
||||
(improvise-felo.2). It
|
||||
measured 3× from 12 to 24 (the table above).
|
||||
- **A fit declines more columns.** `unaffordable_categories` drops the widest
|
||||
category columns once the encoding passes `MAX_FEATURES`. A wide document
|
||||
is fit on fewer of its categories, and the fit says so.
|
||||
- **`cross_product` is exponential in the categories placed on one axis**, and
|
||||
`prune_empty`'s `has_value` matrix is rows × columns. The cap never bounded
|
||||
either.
|
||||
either. Virtualizing the grid is improvise-felo.3.
|
||||
- **Header repeat suppression costs O(levels) per position and level**
|
||||
(`render.rs::shows`). That is O(rows × levels²) per frame, which is small at
|
||||
24.
|
||||
|
||||
The records-mode build's quadratic (improvise-sk32) is not category coupling;
|
||||
it is listed above because this measurement found it.
|
||||
|
||||
The browser adapts where the TUI does not. `#tiles` and `#categories` scroll,
|
||||
and `web/shell.js` charges each column level to the extent.
|
||||
|
||||
|
||||
@@ -736,14 +736,16 @@ is already a category. `suggested_duplicate_category` lives on the pipeline, so
|
||||
the CLI's `separate` uses the same rule.
|
||||
|
||||
**At the category cap, Separate is shown and disabled.** The reported import
|
||||
already had 12 regular categories, which is `MAX_CATEGORIES`. Option (b) adds a
|
||||
had 12 regular categories, which was `MAX_CATEGORIES` when this was written.
|
||||
Option (b) adds a
|
||||
**regular** category, and the user declined a hidden virtual one. So at the cap
|
||||
the option is drawn "(unavailable)" with its reason and remedy: go back and
|
||||
Skip a column or make it a Measure, or choose Sum. The reason is decided in
|
||||
`ImportWizard::duplicate_options`, so every front end words it the same way.
|
||||
This is the conservative reading, and it is **an open question for the user**:
|
||||
lifting the cap for this one category, or counting it outside the cap, is a
|
||||
model-layer decision this ticket did not take.
|
||||
This was the conservative reading, and it left an open question for the user.
|
||||
**The user answered it on 2026-09-25 by raising the cap to 24**
|
||||
(improvise-felo.1), so "keep separate" is available for the reported import
|
||||
now. The option is still disabled for any import that fills the new cap.
|
||||
|
||||
**Headless paths refuse by default.** `improvise import --no-wizard` has
|
||||
nobody to ask, so `--on-duplicate refuse|sum|separate` defaults to `refuse`.
|
||||
|
||||
+1
-1
@@ -581,7 +581,7 @@ and the list can never scroll away. It is by item, not by line, because the
|
||||
wizard state cannot know the panel width that line-level clamping needs. The
|
||||
residual is honest. A **single** item taller than the whole list area, roughly
|
||||
1,500 characters at 80 columns, is still clipped at the panel's bottom. No
|
||||
wizard warning is that long today: a collision tuple is bounded by twelve
|
||||
wizard warning is that long today: a collision tuple is bounded by `MAX_CATEGORIES`
|
||||
categories plus labels, but a label value is not bounded.
|
||||
|
||||
**Every write is clipped to the panel.** The widget draws through `Panel`,
|
||||
|
||||
Reference in New Issue
Block a user