@ai-matrx/records-ui 0.40.0 → 0.42.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,110 @@
1
1
  # Changelog — @ai-matrx/records-ui
2
2
 
3
+ ## 0.42.0
4
+
5
+ **A pipeline table opened as "pick a column", and the board it already had was
6
+ unreachable.**
7
+
8
+ Measured in the real app (lane SCREENS-2, 2026-09-20) against a real pipeline —
9
+ five stages, a moves rule, a requires rule and a WIP limit of 2.
10
+ `custom.pipeline_read` answered `is_pipeline: true` with `stage_field: "stage"`,
11
+ every rule beside it, and the kanban drew
12
+
13
+ > A kanban board needs a Field to make its columns from — pick one and the board
14
+ > appears.
15
+
16
+ Two things stacked. `Board`'s "no grouping field" gate sat ABOVE its pipeline
17
+ branch, and `useIsPipeline` answered `stage.key === groupField` — so a table was
18
+ only a pipeline once somebody had ALREADY guessed which column to group by. The
19
+ store knew the answer the whole time and the screen asked the person for it. A
20
+ board nobody can reach without knowing the answer in advance is not a board.
21
+
22
+ The stage column is now the TABLE's own answer (`custom.table_stage_field`), used
23
+ both to know the table is a pipeline and to know which column its columns come
24
+ from. A view that names its own grouping column still wins — grouping a pipeline
25
+ by its owner is a real thing to want, and it draws the plain board of that column
26
+ and says so. While the table has not answered, NOTHING is claimed in either
27
+ direction: the "pick one" sentence would be a question about to answer itself.
28
+
29
+ `src/pipeline-reach.test.tsx` is at the one seam that decides it
30
+ (`boardColumnChoice`, exported for exactly that reason) and all four clauses fail
31
+ on 0.41.0's bytes.
32
+
33
+ **Consumer action:** none. `ViewSwitcher`'s props are unchanged.
34
+
35
+ ## 0.41.0
36
+
37
+ **The last two product screens that could not work at all, rewritten against the
38
+ doors the store actually has. PRODUCTS rows 13 and 14 (lane SCREENS-2).**
39
+
40
+ Both components shipped, were exported, and were mounted NOWHERE — and neither
41
+ could have worked if it had been.
42
+
43
+ **`ChecklistRunner` kept its own store.** It was written before the store had
44
+ checklists, so it built one out of the generic work-template doors and kept the
45
+ run in a package-owned Table (`records_ui_checklist_run`) whose columns were
46
+ `step_ids` as a JSON string that `JSON.parse` decided the steps from. That is the
47
+ same defect `ActionInbox` had — a second store beside the store — and it meant the
48
+ screen could do none of the things a checklist is FOR: no roles, so no step
49
+ belonged to anybody by their part in the process; no due dates, so "day one" and
50
+ "by Friday" had nowhere to live; no dependencies, so a step could be ticked before
51
+ the one it waits for and nothing had told the store to refuse it; no requirements,
52
+ so "done" was a person clicking a word; no trigger, so a run started by hand every
53
+ time.
54
+
55
+ It is now three mounts of one component over the store's own nine checklist doors:
56
+ the **record page** (the checklists running on this record, and the templates that
57
+ could be started on it), the **table's own Checklists rail** (`ChecklistsPanel` —
58
+ the templates, the runs, the progress, and a plain-rows editor that asks
59
+ `custom.checklist_refusal` on every change so the store's sentence arrives before
60
+ the save), and the **inbox** (`MyChecklistSteps` — a checklist step is a work item,
61
+ so it reaches its owner where her approvals already are, asked through the door
62
+ that also knows what the step asks for and whether it may be finished).
63
+
64
+ Nothing is decided on the screen. `may_complete` and `refusal` are the store's
65
+ answers per step and per seat, and `blocked_by` is what tells the door's two kinds
66
+ of "no" apart: *waiting on another step*, which has no control at all, and *asks
67
+ you to say what you did*, which is the box beside the button. A screen that read
68
+ the sentence's wording would be a second opinion, and it would be the comfortable
69
+ one — the one nobody can be refused by.
70
+
71
+ **`BookingSlots` was a slot picker for a person who has no account.** It called
72
+ `tableList`, `personKernelId`, `recordWrite`, `workSlotsDeclare`, `workSlotHolds`,
73
+ `workSlotHold` and `workSlotRelease` — seven doors granted to `authenticated` —
74
+ for a VISITOR, who can reach none of them. It also built its own grid of times in
75
+ the browser from an `availability` prop, which is a second idea of what is on
76
+ offer, and declared a THIRD slots Table under its own slug beside the one
77
+ `custom.booking_declare` finds-or-makes, so a page opened through the component and
78
+ a page opened through the link protected different indexes.
79
+
80
+ It is now the owner's panel, the way `FormsPanel` is for forms: `custom.bookings`
81
+ for the pages, their four counts and the next appointment in words in the
82
+ ORGANIZATION's own zone, the visitor's link, and open/close through
83
+ `custom.anon_publish` — offered only where `custom.my_levels` answered `admin`, and
84
+ never while that door is still in flight. It mounts on the Records home (absent
85
+ when the organization has none) and on the bookings table's own rail. The picker is
86
+ the public `/b/<id>` route's, server-fed and server-lane; a suite clause fails if
87
+ any of those nine doors is ever called from here again.
88
+
89
+ **Consumer action:** `CHECKLIST_TABLE` is gone, and so is the run store it
90
+ described — a run is `custom.checklist_runs`' and its steps are work items.
91
+ `ChecklistSpec` / `ChecklistStepSpec` are no longer re-declared here; import them
92
+ from `@ai-matrx/records`, which is where the store's own judge
93
+ (`custom.checklist_refusal`) reads them from. `BookingSlots` no longer takes
94
+ `form` or `availability`; it takes an optional `tableId` and nothing else.
95
+ `ChecklistRunner`'s `seed` prop is gone — a checklist is declared through
96
+ `checklistDeclare`, whole, and judged before a single step is written.
97
+
98
+ **The proof.** `demo/checklists.test.tsx` and `demo/bookings.test.tsx` are in the
99
+ blocking gate against RECORDED REAL answers taken from the one database by
100
+ `demo/fixtures/*.record.sql`, from the `authenticated` seat, through the doors
101
+ alone, rolled back. The checklist recording is a two-seat run — an admin describes
102
+ onboarding once, a new hire record arrives, a run starts by itself, four steps land
103
+ on two real people, and the same run answers differently from each of their seats.
104
+ The booking recording is a whole lifecycle in five snapshots: open, held, booked,
105
+ rescheduled, cancelled. `src/checklists.red.tsx` and `src/bookings.red.tsx` are the
106
+ red twins; all six clauses fail on these bytes.
107
+
3
108
  ## 0.40.0
4
109
 
5
110
  **Pressing "Settings" on a table crashed the whole page, and had since the