@lotics/ui 27.17.0 → 28.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -381,88 +381,59 @@ When work crosses departments (sales → operations → accounting), the HANDOFF
381
381
  changing desks — never an inbox, a notification, or a copied task. Two types:
382
382
 
383
383
  **(A) Same entity** → a STAGE field on the shared record: sections carry OWNER dot tags, and the
384
- handoff is MANAGED AS TASKS — each desk's checklist on the record. The **`Task`** compound owns
385
- the list geometry (the control column, the indent, and `density`44px targets by default)
386
- compose it, never hand-roll the row. A **`TaskItem`** carries a `TaskStatus` (a `CheckCircle` a
387
- read-only ring when it has no `onChange`), a `TaskTitle` (an `InlineTextInput`,
388
- or the title TEXT as a string child — `<TaskTitle struck={done}>{label}</TaskTitle>` is the
389
- read-only form, and the compound owns its inset and band, so never hand-roll a `Text` title) and
390
- a `TaskActions` menu never a decorative progress strip. The fields the desk SETS (the
391
- assignee `InlineMemberSelect`, the due date) hang UNDER the row as `TaskSubRow`s, which reflow on
392
- their own, so the drawer and the record page run the SAME composition. `CaptureRow` closes the
393
- list as its add-affordance.
394
-
395
- **A row's first line is a BAND** (44px comfortable, 32 dense): both gutter controls centre in it,
396
- `TaskTitle` claims it, and everything else caption, detail, nested list, a title's wrapped
397
- second line hangs below it. That is what keeps a column of controls straight down a list of
398
- mixed-height rows, so a control never drifts into the gap under the title it belongs to.
399
-
400
- A task's own free text is its TITLE, a **`TaskCaption`** or a **`TaskDetail`** — there is no
401
- fourth place to write about the TASK, because a fourth place gets written in twice. `TaskCaption`
402
- is the row's state IN WORDS ("3 of 5 papers received", "waiting on the yard") on its own line
403
- under the title; it is not a field, because a field is a NAMED VALUE the reader sets and a caption
404
- is a SENTENCE about one row labelling prose makes it read as a field nobody can edit. A sentence
405
- about one FIELD is not a caption either: it is that sub-row's own `description` / `warning` /
406
- `error`, which is why the sub-row carries all three.
407
-
408
- **THE ROW CARRIES THE TITLE; THE FIELDS THE USER CAN SET ARE SUB-ROWS BENEATH IT.** A field
409
- belonging to ONE task its due date, its assignee, a portal login, a reference number hangs
410
- under it as a **`TaskSubRow`** (`label`, the control, `description` / `warning` / `error`),
411
- indented ONE step, with the NAME beside its VALUE so the eye pairs them. Belonging is expressed by
412
- that indentation, which is the same step a nested `TaskList` takes one device, at every depth.
413
-
414
- **The label column belongs to the LIST, not to the row** `TaskList labelWidth`, defaulting to
415
- `DETAIL_LABEL_WIDTH` (130), inherited to every depth, exactly as `DetailTable labelWidth` is the
416
- record's. Every sub-row on the surface therefore starts its value on ONE x, and a name longer than
417
- the column WRAPS inside it instead of pushing its own value right. A column each row sized to its
418
- own words is not a column: it lined up the labels of a task whose names happened to be short and
419
- staggered every other one, and a vocabulary with longer field names than English staggered nearly
420
- all of them. Raise it once, on the list, for a vocabulary that genuinely needs more. The value
421
- takes the slack from a readable minimum, dropping onto its own line under the label on a surface
422
- too narrow to seat both. Use the `Inline*` editor
423
- belongs to a grid.
424
-
425
- **A TASK'S FIELD ANNOTATES EXACTLY LIKE A RECORD'S FIELD.** `TaskSubRow` carries the same
426
- `description` / `warning` / `error` as `DetailRow`, from one shared implementationsame tones,
427
- same severity order (error nearest the control, then warning, then the guidance), same alert
428
- semantics. A fault in ONE field says so on that field. Demoting it into a `TaskCaption` — a
429
- sentence about the whole ROW — says something different, and that asymmetry is what forced apps
430
- to do it.
431
-
432
- **Anything that needs SCANNABLE COLUMNS is a `Table`, not a `TaskList`.** The compound once
433
- carried a declared VALUE column so cells lined up down the list; it aligned, and it read worse —
434
- each name ended up a quarter of the surface from its control, sized for the widest value on the
435
- page. Comparing the same four values across twenty rows is a table's job. A `DetailTable` inside a
436
- `TaskDetail` is the same mistake in miniature: the list already HAS a label column, so a second
437
- one lands a label and a control at two more x positions matching nothing above them — a form
438
- pasted into a list, and with sub-row annotations there is nothing left for it to say.
439
- `TaskDetail` keeps the FREE-FORM block (a chart, a table, a form with its own submit) — it has no
440
- name to hang on the indent, so a rule down its left edge is what ties it to the row.
441
-
442
- **The ⋯ is a COLUMN — the mirror of the control gutter.** Both pinned controls sit outside the
443
- row's flow and the ROW reserves each edge (`controlWidth` on the left, `actionWidth` on the
444
- right, each plus the row gap), leaving ONE content box between them that every line spans exactly:
445
- the title, a caption, a sub-row, a detail block, a nested list. That is what keeps a list where
446
- only SOME rows carry a menu straight — a menu-less row's content ends on the same x as a
447
- menu-carrying one's, and so does everything hanging beneath either. A nested list hands the
448
- parent's reservation back before its own rows re-take it, so the column does not step inward per
449
- level. Declare `actionWidth={0}` when NO row in the list carries actions, so it pays nothing for a
450
- column it never uses.
451
-
452
- **Subtasks are TASKS** — nest a `TaskList` inside the `TaskItem`, and the child carries fields,
453
- a menu and children of its own. There is no separate subtask shape to outgrow, and no built-in
454
- chevron: collapsing is the app's call (hold a boolean, render the nested list or don't).
455
-
456
- **State flows from the LEAVES.** Where a row's position is computable from what it owns, DERIVE
457
- it — a stored status is a second copy of what the fields already say, and two copies drift. Give
458
- the parent's ring the bulk gesture where its children ARE the fact (tick it, every child ticks);
459
- where the ring answers a DIFFERENT field the children do not determine — a date, say — coupling
460
- them asserts something the operator never said.
461
-
462
- **A sub-row holds a CONTROL.** Where exactly one field determines a row's status, the sub-row IS
463
- that field's editor: a read-only copy of it elsewhere on the row puts one value on screen twice,
464
- under two names. Everything else derived is prose in `TaskCaption` — a read-only pill given a
465
- field's label reads as pressable when it is not. A `Badge` INSIDE the editor (an
384
+ handoff is MANAGED AS A CHECKLIST — each desk's work on the record. **`checklist`** owns the row
385
+ geometry (the ring column, the connecting line, the rhythm)compose it, never hand-roll the row.
386
+ A **`ChecklistItem`** carries its title, its own stamp (`trailing`), a short `meta` and an
387
+ optional (`menu`); **`ChecklistGroup`** names a phase above the rows it heads. `CaptureRow`
388
+ closes the list as its add-affordance.
389
+
390
+ **`connected` decides which shape you are building.** ON for one record walking positions the
391
+ line asserts sequence, which is what a desk handoff IS. OFF for N items ticked in any order, where
392
+ a line claims an order the work does not have. It is the same compound either way; they were two
393
+ families until the anatomy turned out to be identical.
394
+
395
+ **A GROUP is a name and nothing else.** No control: a phase owns no completion of its own, so a
396
+ ring there reports without respondingand one identical to the pressable rings beneath it
397
+ invites the press it refuses, which is worse than showing nothing. No BODY: a condition or an act
398
+ hung off a heading leaves the reader working out which of the rows below it they were about. The
399
+ row that OWES the work carries all of it — its wait (`meta`), its condition (`ChecklistNote`) and
400
+ the act that leaves it (`ChecklistActions`).
401
+
402
+ **ROWS TICK ONE AT A TIME.** A parent that ticked its children wrote what the reader never said:
403
+ on a dated ladder, today's date onto milestones that happened on days nobody recorded. Where the
404
+ run is a SEQUENCE, derive position from the highest stamp instead one click then marks
405
+ everything below it, and a rung the record passed without a recorded day shows a BLANK date, which
406
+ is the honest answer to "when" and stays one click from being filled. That is the whole of the
407
+ bulk gesture, and it invents nothing.
408
+
409
+ **A CHECKLIST REPORTS; IT DOES NOT COLLECT, AND IT DOES NOT PREVIEW.** A field some section owns
410
+ an assignee, an address, a tax ID is NAMED as a gap by a **`ChecklistNote`** whose `action` jumps
411
+ to that section. Never an editor in the row: two edit surfaces for one fact, and every row becomes
412
+ two things at once (a status and a form) with nothing to say which one the reader is in. Never a
413
+ rendered value either — an avatar or a badge is a COPY that has to be kept in step with the
414
+ field's real home, and readers start treating the list as the place the value lives. Two
415
+ exceptions, both narrow: **`ChecklistItem.trailing`** for the row's OWN stamp (a tick writes today,
416
+ so a run filled in after the fact needs the correction in reach), and **`ChecklistField`** for a
417
+ value with NO other home a portal login created at that step, unreachable otherwise.
418
+
419
+ **Prose that grows owns its own line.** `ChecklistItem.meta` is two words riding the title (who it
420
+ waits on, how long); anything that lengthens with the data "Needs: Tax ID, Delivery address"
421
+ is a `ChecklistNote`, because a sentence on the title's line wraps into the title and the row stops
422
+ scanning. Neither takes a LABEL: a field is a named value the reader sets, and labelling prose
423
+ makes it read as a field nobody can edit.
424
+
425
+ **Anything that needs SCANNABLE COLUMNS is a `Table`.** The compound once carried a declared VALUE
426
+ column so cells lined up down the list; it aligned, and it read worse each name ended a quarter
427
+ of the surface from its control, sized for the widest value on the page. Comparing the same four
428
+ values across twenty rows is a table's job.
429
+
430
+ **State flows from the LEAVES.** Where a row's position is computable from what it owns, DERIVE it
431
+ — a stored status is a second copy of what the fields already say, and two copies drift.
432
+
433
+ **One value, one place on the row.** Where a row carries a field at all (`ChecklistField`, the
434
+ no-other-home case), that editor IS the value: a read-only copy of it elsewhere on the row puts
435
+ one value on screen twice, under two names. Everything else derived is prose in a
436
+ `ChecklistNote` a read-only pill given a field's label reads as pressable when it is not. A `Badge` INSIDE the editor (an
466
437
  `InlineSelect renderSelected`) is fine: it inherits the control's own inset.
467
438
 
468
439
  **A status reports what is OUTSTANDING, never what is settled.** A finished row already says so
@@ -485,7 +456,7 @@ record type) — no human types them; common-but-OPTIONAL tasks appear as `Sugge
485
456
  the list — a PILL, never a row, so a suggestion can't be mistaken for a task (tap = materialize,
486
457
  ✕ = dismiss for this record; already-present labels filter out; suggestions never count in
487
458
  done/total and pause while a filter narrows the view) — the same suggestion grammar as the billing
488
- Standard pill. `TaskActions` holds an `ActionMenu` (Delete lives BEHIND it, danger-styled and last
459
+ Standard pill. `ChecklistItem.menu` holds an `ActionMenu` (Delete lives BEHIND it, danger-styled and last
489
460
  — never a bare ✕ a stray tap can hit), which completes the list's CRUD.
490
461
 
491
462
  Open tasks INFORM the handoff, they NEVER block it: the CTA stays enabled, the count warns, and
@@ -494,10 +465,9 @@ open tasks carry over. The handoff CTA opens a DIALOG for the receiving desk (as
494
465
  the record left this register.
495
466
 
496
467
  Tasks PEEK from the register: the done/total column is a pressable compact-`ProgressBar` trigger
497
- whose popover holds the same `Task` list — every `TaskItem`'s ring `TaskStatus`, struck
498
- `InlineTextInput` `TaskTitle` (flex), a quick-reassign `InlineMemberSelect` in a `TaskSubRow`
499
- under it — no expandable rows (tags/files depth is
500
- the Task list template's lesson, not the peek's); the popover body is `PopoverContent`'s own
468
+ whose popover holds the same `Checklist` — every `ChecklistItem`'s ring and title, and nothing a
469
+ section already owns (a reassign belongs to the record, not to a peek over fifty rows) — no
470
+ expandable rows (tags/files depth is the task board's lesson, not the peek's); the popover body is `PopoverContent`'s own
501
471
  ScrollView (`disableBodyScroll` is ONLY for children that manage their own scroll, like
502
472
  `OptionList`). The DRAWER carries a real Tasks SECTION in the Record template's shape (heading +
503
473
  the compact meter + the same checklist) — one shared task state per record feeds the column, the
package/docs/templates.md CHANGED
@@ -198,8 +198,15 @@ screens — register, per-row action, gated selection, and act-on-many in one. T
198
198
 
199
199
  - **One toolbar row** — search + a status `Select` + facet `FilterChip`s LEFT, the New CTA
200
200
  RIGHT; a light `SummaryLine` of the filtered view below.
201
- - **A sortable, `Divider`-separated `Table`** where the record's KEY/identifier is the FIRST
202
- column and every row carries a leading checkbox; a row that can't take the bulk action gets a
201
+ - **A sortable, `Divider`-separated `Table`** where the record's SUBJECT is the first column —
202
+ who or what the record is FOR, because that is what a reader scans for and what they say out
203
+ loud ("the Harbor Freight one", never "RC-2026-0041"). The KEY is how the SYSTEM refers to the
204
+ record, so it rides the identity cell's supporting line, muted, where the other supporting
205
+ values live; it does NOT take a column of its own, and it is never the row's name. It also does
206
+ not SHRINK there — a key is quoted whole or it is not a key, so a long phone number gives way
207
+ first (it has a `CopyButton` handing over the full value regardless). The record surface names
208
+ itself the same way, or the two disagree about what a record is called. Every row carries a
209
+ leading checkbox; a row that can't take the bulk action gets a
203
210
  **disabled** checkbox (the same gating as any blocked line). A row's status is
204
211
  `Badge variant="dot"` — never the tonal `Badge` (that's the drawer/header twin; → [composition
205
212
  grammar §"Status indicators have a WEIGHT"](./composition.md)) — and the SAME dot vocabulary
@@ -219,15 +226,18 @@ screens — register, per-row action, gated selection, and act-on-many in one. T
219
226
  [`tpl_record`](../examples/tpl_record.tsx) in `chrome="drawer"`, not a copy of it. Same
220
227
  sections, same order, same rules, because it is the same component: `<TplRecord
221
228
  chrome="drawer" code={row.id} />`. A hand-built second record surface is exactly how the two
222
- drifted apart — a checklist on one side and a `Pipeline` on the other, a reference as a
229
+ drifted apart — the progress ladder grouped one way here and flat there, a reference as a
223
230
  section here and a field there — so the register owns the REGISTER and nothing else.
224
- - What the chrome flag changes is only what a nested surface must not do: comments become the
225
- LAST SECTION of the drawer's own scroller (a `Drawer` has no second gutter to dock them
226
- into), and the back button is left to the Drawer's header. Everything else follows from
231
+ - What the chrome flag changes is only what a nested surface must not do: the back button is
232
+ left to the Drawer's header, since two exits is two exits. Everything else follows from
227
233
  width — the layout measures its CONTAINER via `onLayout`, never the window, so the outline
228
- rail, the docked discussion and the mirrored gutters collapse on their own, and the section
229
- picker is a popover ANCHORED to its bar button rather than a full-page `Modal` that would
230
- escape the drawer.
234
+ rail and the mirrored gutters collapse on their own, and the section picker is a popover
235
+ ANCHORED to its bar button rather than a full-page `Modal` that would escape the drawer.
236
+ **The discussion follows the same measure**: docked beside the record where there is room for
237
+ its column, and a SECTION under General where there is not — which a drawer always is. It is
238
+ never behind a control. It was briefly a toggle in the top-right of a narrow page and a
239
+ body-SWAP inside a drawer; both made the reader know a control existed, press it, and give up
240
+ the record to read a note, which is where an unread note goes to be missed.
231
241
  - **Linked records** still push an editable screen for that record inside the drawer via the
232
242
  hosted `ScreenRouter` — while `canGoBack` the drawer header swaps to a back button + the
233
243
  pushed id and the ◀ ▶ sequencer hides; back pops with scroll preserved.
@@ -314,12 +324,19 @@ billing, and quick-capture templates. Top → bottom:
314
324
  (author-only edit/delete; attachments as a pressable `FileGrid` → gallery preview; a
315
325
  file-capable edit form injected via `renderEditForm`) + THE kit `Composer` (attach via
316
326
  `actionsButton`, staged files in its `files` slot) — never a bespoke comment box.
317
- - **Progress** — the desk handoff as the ordered positions it is: a bare `Pipeline` over
318
- Sales Operations Accounting. Each REACHED stage owns the facts it stamps as
319
- `PipelineField`s (taken-on `InlineDatePicker`, owner `InlineMemberSelect`) and keeps them
320
- editable once the record has moved on; the LIVE one adds its condition (`PipelineNote`, e.g.
321
- past the due date) and the single act that leaves it (`PipelineActions` the handoff dialog).
322
- An unreached stage is its title alone. `meta` carries how long the desk has held it prose
327
+ - **Progress** — directly UNDER General, because where the record SITS is the second question a
328
+ reader has after what it IS, ahead of its files, its route and its money, which are all
329
+ reference. The desk handoff as the ordered positions it is: a `Checklist connected` where the
330
+ desks are `ChecklistGroup`s (Sales Operations Accounting) and the milestones they produce
331
+ are the rows. A GROUP carries no COMPLETION control (a phase owns none, and
332
+ a ring that never responds invites the press it refuses) and no body (a condition hung off a
333
+ heading leaves the reader working out which row it was about). The row that OWES the work
334
+ carries all three: how long it has been owed (`meta`), its condition (`ChecklistNote`, e.g.
335
+ past the due date — with an `action` jumping to the section that owns a missing field rather
336
+ than editing it here) and the single act that leaves the desk (`ChecklistActions` → the handoff
337
+ dialog). Rows tick ONE at a time and position is the HIGHEST stamp, so one click marks
338
+ everything below it without writing dates nobody recorded; a rung it passes shows a BLANK date,
339
+ which is the honest answer to "when" and stays one click from being filled. `meta` is prose
323
340
  the reader can't set, never the date that the stage's own field already shows. See § The
324
341
  handoff shape for the rules; for a record that genuinely needs a CHECKLIST, the task-list
325
342
  grammar is worked in `tpl_item_list`.
@@ -405,22 +422,21 @@ billing, and quick-capture templates. Top → bottom:
405
422
  REPLACES the set — derived paperwork, never intake; the desk register above keeps what
406
423
  arrived. **READINESS**: a form declares the RECORD FIELDS it reads (`needs`); the fields'
407
424
  HOME stays their DATA section (the colocation law) with descriptions naming their
408
- consumers ("printed on the delivery note"). The picker rows ride `TaskList`/`TaskItem`
409
- (`controlWidth={24}` for the `CheckboxInput` in `TaskStatus`, and `actionWidth={0}` because no
410
- row here carries a ⋯, so the list pays nothing for the action gutter) the compound owns the
411
- row geometry and both gutters; hand-rolling the anatomy is how alignment drifts. Warning and fix are CO-LOCATED on the row. The mark NAMES what's missing a
412
- **`TaskCaption`**, not a field: 13px `circle-alert` + "Needs: …" the actual field labels,
413
- muted at rest so gaps show WITHOUT checking, warning once checked because it now blocks. It is
414
- a SENTENCE about the row, and a `TaskSubRow` is a NAMED value the reader sets, so prose given a
415
- label reads as a field nobody can edit. The FIX sits
416
- right under it in the row's `TaskDetail` — an `Inset` (a FORM surface, NEVER a `Callout`:
417
- a warning Callout is an ARIA `alert`, wrong around a form) with a `FormTextInput` per gap
418
- (label + the consumer hint as `description`) and a "Save fields" (secondary the section
419
- keeps ONE primary, disabled while every draft is empty). Save writes the record fields
420
- (their home rows show the values); the need resolves, the mark clears, the fill drops
421
- away. Drafts are keyed BY FIELD, so a field two checked forms share is entered ONCE and
422
- one Save resolves both. A ready form stays SILENT. Missing fields are the gating law's
423
- DEGRADED-BUT-VALID case (they print blank, filled by hand later): Create stays ENABLED, a
425
+ consumers ("printed on the delivery note"). The picker rows ride a
426
+ `Checklist connected={false} mark="select"` the SAME compound as Progress, TWO axes apart.
427
+ Unconnected because these forms are a SET the user picks from rather than a sequence, and a
428
+ line between them would claim an order the work does not have; `select` because picking a form
429
+ is a CHOICE, and a filled ring there would read as work already carried out to a reader who
430
+ learned what a ring means one section above. The row NAMES what is missing in a `ChecklistNote` — "Needs: …"
431
+ the actual field labels, muted at rest so gaps show WITHOUT checking, warning once checked
432
+ because it now blocks and points at the section that owns those fields.
433
+
434
+ **It does not collect them.** The row briefly opened a form of its own here, which made every
435
+ row two things at once (a status and a form) with nothing to say which one the reader was in,
436
+ and put an editor beside a field's real home where its description and its neighbours live. A
437
+ checklist REPORTS; the section that owns a value COLLECTS it. A ready form stays SILENT.
438
+
439
+ Missing fields are the gating law's DEGRADED-BUT-VALID case (they print blank, filled by hand later): Create stays ENABLED, a
424
440
  co-located warning `Callout` states the consequence, and the press CONFIRMS via `Alert`.
425
441
  Only an empty pick disables, and silently. A form can also be DATA-conditional (the hazardous-goods note renders only
426
442
  while the record's Hazardous goods boolean is set — record data may reshape the list,
@@ -471,40 +487,62 @@ billing, and quick-capture templates. Top → bottom:
471
487
  below that it collapses to the pinned bar. Sizing the column is the SHELL's job — inner
472
488
  blocks are plain `width: "100%"`, never a second `maxWidth` + `alignSelf: "center"`.
473
489
 
474
- ### The handoff shape — `Pipeline`, and where it lives
490
+ ### The handoff shape — a CONNECTED checklist, and where it lives
475
491
 
476
- One record walking N ordered stages, where **the stage decides what you can see and do**: work
477
- passed between desks — an application through intake → review → production → filing, a claim
492
+ One record walking N ordered positions, where **the position decides what you can see and do**:
493
+ work passed between desks — an application through intake → review → production → filing, a claim
478
494
  through submitted → assessed → paid.
479
495
 
480
- It is NOT its own template. A handoff is something a RECORD does, so it renders as one section
481
- OF that record — see `tpl_record` § Progress, where the desks (Sales → Operations → Accounting)
482
- become the stages, each owning the facts it stamps (taken-on, owner) and the live one carrying
483
- the act that leaves it.
484
-
485
- **It replaced a per-desk CHECKLIST, and that swap is the lesson.** Ticking boxes described the
486
- WORK; it never said where the record SAT, so the reader had to infer position from which group
487
- still had unticked rows — and the handoff CTA sat in a different section entirely, the act
488
- divorced from the state that gated it. A stage says the position outright, and the act rides the
489
- stage it belongs to. Reach for a checklist only when the rows are genuinely N independent
490
- tickable items (`TaskList`); a record's own progress is a pipeline.
491
-
492
- Built on the `Pipeline` compound (`Pipeline`, `PipelineStage`, `PipelineField`,
493
- `PipelineNote`, `PipelineActions`), which composes over `Stepper` `Stepper` renders POSITION,
496
+ It is NOT its own template. A handoff is something a RECORD does, so it renders as one section OF
497
+ that record — see `tpl_record` § Progress, where the desks (Sales → Operations → Accounting) are
498
+ `ChecklistGroup`s and the milestones they produce are the rows.
499
+
500
+ **Two levels, because a desk and a milestone are not peers.** The ladder was briefly one flat run
501
+ of eight "Operations" beside "Collected" which asked the reader to know which name was a PLACE
502
+ and which was an EVENT. Grouping the milestones under the desk that produces them says it in the
503
+ shape instead.
504
+
505
+ **A group is a name and nothing else.** No control: a phase owns no completion of its own, so any
506
+ ring it wore would report without responding and one identical to the pressable rings beneath it
507
+ invites the press it refuses, which is worse than showing nothing, because the reader clicks and
508
+ the product says nothing back. No BODY either: a condition or an act hung off a heading leaves the
509
+ reader working out which of the rows below it they were about.
510
+
511
+ **Rows tick ONE at a time, and position is the highest stamp.** That is what lets one click say
512
+ "everything up to here": ticking `Delivered` puts the record there and the rungs below it read
513
+ done immediately. The alternative — a parent tick that fills its children — marks the same rows
514
+ but INVENTS their dates, writing today onto milestones that happened on days nobody recorded. A
515
+ rung the record passed without a recorded day shows a BLANK date, which is the honest answer to
516
+ "when" and stays one click from being filled.
517
+
518
+ **A checklist REPORTS.** It does not collect and it does not preview: a field some section owns is
519
+ NAMED as a gap by a `ChecklistNote` whose `action` jumps there, never edited in the row and never
520
+ rendered as a value. The row's OWN stamp (`trailing`) and a value with no other home
521
+ (`ChecklistField`) are the two exceptions.
522
+
523
+ **It replaced a per-desk CHECKLIST without the line, and that swap is the lesson.** Ticking boxes
524
+ described the WORK; it never said where the record SAT, so the reader inferred position from which
525
+ group still had unticked rows — and the handoff CTA sat in a different section entirely, the act
526
+ divorced from the state that gated it. A connected run says the position outright, and the act
527
+ rides the row that owes it. `connected={false}` is for rows that are genuinely N independent
528
+ items; a record's own progress asserts sequence.
529
+
530
+ Built on `checklist` (`Checklist`, `ChecklistGroup`, `ChecklistItem`, `ChecklistNote`,
531
+ `ChecklistActions`, `ChecklistField`), which composes over `Stepper` — `Stepper` renders POSITION,
494
532
  this adds the anatomy that turns a position into a workspace.
495
533
 
496
534
  Three rules the anatomy holds, each learned from getting it wrong:
497
535
 
498
- - **Only the CURRENT stage carries an act.** A control on an unreached stage invites acting out
499
- of order — and where the stage is derived from the highest stamp, one stray press jumps the
500
- record past the desk that owns it. On a passed stage it re-offers something already done.
501
- - **A condition belongs to its stage.** "Sent back", "rejected", "waiting on the customer" are
502
- facts about ONE stage, so they render inside it (`PipelineNote`) rather than as a `Callout`
536
+ - **Only the OWED row carries an act.** A control on an unreached row invites acting out of
537
+ order — and where position is derived from the highest stamp, one stray press jumps the record
538
+ past the desk that owns it. On a passed row it re-offers something already done.
539
+ - **A condition belongs to its row.** "Sent back", "rejected", "waiting on the customer" are
540
+ facts about ONE position, so they render inside it (`ChecklistNote`) rather than as a `Callout`
503
541
  above the run, which reads as "something is wrong with this record" and sits nowhere near the
504
- control that answers it.
505
- - **A passed stage stays correctable** — its date (clearable, which is how you walk a record
506
- BACK) and any field it owns. Otherwise a value typed wrong becomes unreachable the moment the
507
- record moves on, and the only fix is direct table access.
542
+ control that answers it — and nowhere near enough to say WHICH row it is about.
543
+ - **A passed row stays correctable** — its stamp is editable, which is how a date recorded wrong
544
+ gets fixed and how a record walks BACK. Otherwise a value typed wrong becomes unreachable the
545
+ moment the record moves on, and the only fix is direct table access.
508
546
  - **The stage that OPENS gets stamped by the act that opened it**, and the TERMINAL act is not
509
547
  a handoff. Handing off asks whom (a dialog) and writes that answer into the receiving stage's
510
548
  own fields — coming up blank re-asks a question just answered. Finishing has no receiving