@ai-matrx/records-ui 0.43.0 → 0.47.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,154 @@
1
1
  # Changelog — @ai-matrx/records-ui
2
2
 
3
+ ## 0.47.0
4
+
5
+ Carries 0.45.0 and 0.46.0, neither of which reached npm: the publish of 0.45.0
6
+ failed on a live clause that had gone stale under a store change (see the last
7
+ item), and 0.46.0 was cut behind it.
8
+
9
+ **A refusal with two remedies, one of them wrong.**
10
+
11
+ A plumbing company wants to give ONE customer view access to the jobs table her
12
+ work is on. She has an account; she is not in their organization.
13
+ `custom.share_grant` refuses, and it refuses WELL — measured verbatim on the live
14
+ store: *"That person is not in this organization, so they cannot be given access
15
+ to this table yet."*, with three ways forward in its hint: invite them, share
16
+ with their organization instead, or — if they are a client rather than a
17
+ colleague — put them in a portal.
18
+
19
+ The screen threw all of that away, in three separate ways, all of them in
20
+ `plainWords.ts` and all of them fixed here:
21
+
22
+ 1. **Two remedies, one wrong.** The formatter printed the door's ways forward AND
23
+ then its own table's *"Change the value so it passes, then try again"*, which
24
+ is not a thing anybody can do about a membership. A person follows the last
25
+ sentence they read. The DOOR's hint is the remedy now whenever it survives the
26
+ machine-identity filter; the table is the fallback it always should have been.
27
+ 2. **One footnote binned the sentence around it.** The hint's human half carried
28
+ `(VIS-23)`, so the whole clause was judged machine identity and dropped — which
29
+ is why the plumber got no remedy at all. A bracketed contract id is a
30
+ footnote: it is lifted out, the sentence is kept, and the id still reaches the
31
+ engineer.
32
+ 3. **The cleaner re-wrote a sentence it had no reason to touch.** It splits on
33
+ `", so "` — one of the store's own `format()` joins, and also how ordinary
34
+ English joins two clauses — and rejoins with `". "`. So every person, on every
35
+ such refusal, read *"That person is not in this organization. they cannot be
36
+ given access to this table yet."* A cleaner that dropped nothing now changes
37
+ nothing.
38
+
39
+ `src/one-remedy.test.tsx` runs all five clauses on that exact measured refusal.
40
+
41
+ **A live clause that had gone stale, and was blocking every publish.**
42
+
43
+ `demo/live-smoke.test.tsx` asserted that a table declared with one column NAME has
44
+ no columns — true until lane LIMITS-FIX landed "a table's declared fields exist"
45
+ (2026-09-21, and the root cause behind crew C's fifty-one rows under "this table
46
+ has no columns yet"). The store cannot produce that state any more. The clause
47
+ asserts what it produces instead, which is strictly the stronger of the two, and
48
+ `declareTableWithNoColumns` — a name that had become a lie — is
49
+ `declareTableWithItsFirstColumn`.
50
+
51
+ **Consumer action:** none.
52
+
53
+ ## 0.45.0
54
+
55
+ **The record grid vanished when you looked at a dashboard and then opened a panel.**
56
+
57
+ Ridgeline Physical Therapy keeps ten patients in a table. Its owner pressed
58
+ Dashboards, then Checklists to compare the two panels, and the patients were
59
+ gone — with no New record button and no way back but a reload. Reproduced
60
+ headless on the live app: `aria-pressed` was `"true"` on Dashboards, ABSENT on
61
+ Checklists, no grid in the document.
62
+
63
+ That row of buttons was TWO state machines wearing one coat. `main` decided the
64
+ middle of the page, `rail` decided the right-hand panel, nothing joined them,
65
+ and the NINE rail buttons carried no pressed state at all — so the only tab that
66
+ ever looked chosen was the one that was not.
67
+
68
+ `chooseSurface` decides both now and `surfaceChosen` answers, for every button
69
+ in the row, whether it is the chosen one. Opening a panel brings the records
70
+ back (a panel is read BESIDE the records); opening the dashboards over a panel
71
+ leaves the panel alone, because that direction takes nothing away. Pressing the
72
+ chosen button closes it, as it always did. `src/surface-choice.test.tsx`, five
73
+ clauses, all red on 0.44.0.
74
+
75
+ **The Share button was called something it never said.**
76
+
77
+ It read "Share" and carried `aria-label="Share this table"` — and an
78
+ `aria-label` REPLACES the visible text as the accessible name. So a screen
79
+ reader, a voice user saying "click Share", a keyboard palette and every
80
+ automation all resolved a sentence the screen never shows. A crew reported it
81
+ twice as an absent button ("Playwright could not find a clickable, visible
82
+ 'Share' button even though the same label renders as a normal-looking button"),
83
+ and the clinic's front desk never got read access to the patients table.
84
+
85
+ The context is the `title` now, which describes and never renames.
86
+ `scripts/check-label-in-name.mjs` is the census — it carries `--self-test`,
87
+ which plants this exact rename and requires the census to go red on it — and it
88
+ found one more of the same: the grid's Delete button, which read "Delete" and
89
+ was named "Delete this record". Wired into `check:package`, so the class cannot
90
+ come back. A glyph (`+`, `×`) is not a label and is not judged: there
91
+ `aria-label` is the only name there is.
92
+
93
+ **Every cell asked "who?" and never answered.**
94
+
95
+ A crew reading ten real patients: *"Every single cell shows a small 'who?' hover
96
+ badge next to its value instead of a resolved author name, an agent/rule label,
97
+ or even 'system' — the attribution feature is visibly wired up (it renders on
98
+ every cell) but never resolves to anything readable."* They were right, and the
99
+ reason was that nothing ever asked: the badge opened a panel and looked nothing
100
+ up, while `custom.field_history` on those exact patients had been answering
101
+ *created by admin* since the day they were written.
102
+
103
+ It asks now, on the hover or the Tab that already makes it visible, for that one
104
+ cell — so a page of two hundred cells nobody points at costs nothing. `who?` is
105
+ what it says while the question is still a question; the moment it has the
106
+ answer, the answer is what it wears, and the hover carries the whole sentence.
107
+ `src/whoChanged.ts` owns those words for every surface that shows an author: an
108
+ agent ALWAYS names the person it acted for, the platform is "the system", a
109
+ person the door did not name is resolved through the app's one
110
+ organization-scoped roster (the `members` port), and a uuid is never printed at
111
+ anybody.
112
+
113
+ **Opening a table showed an error about a column in a table you will never see.**
114
+
115
+ The Alvarado-Chen family opened their recipes and met *"That already exists —
116
+ This table already has a field called 'Name'"*, every time. `Name` is the first
117
+ column of the PACKAGE's own bookkeeping table (`records_ui_view`, where a saved
118
+ view is a record), which `ViewBar` levels on every table page: the store's read
119
+ answered without the field, the store's write answered 23505 with it, and that
120
+ refusal was painted over the family's recipes.
121
+
122
+ Two classes, both closed. A step written to be idempotent no longer calls its own
123
+ desired end state a failure — 23505 from `field_declare` means exactly what
124
+ `addMissingFields` was trying to arrange, and every other refusal still comes
125
+ straight back out. And bookkeeping is never the person's error: a refusal
126
+ levelling the package's own table degrades the saved views with one sentence
127
+ (`SAVED_VIEWS_UNAVAILABLE`) and leaves the table's own screen alone.
128
+ `src/ensure-idempotent.test.tsx`, two clauses, red on 0.44.0.
129
+
130
+ **Consumer action:** none. No export changed — `chooseSurface`, `surfaceChosen`,
131
+ `WhoChangedSource`, `useWhoChanged` and the `whoChanged` vocabulary are added.
132
+
133
+ ## 0.44.0
134
+
135
+ **Pressing Open in the inbox landed you on the table with the record still shut.**
136
+
137
+ `ActionInbox` has always handed its host `onOpenRecord(recordId, tableId)`, and
138
+ the app has always routed that to `/data-v2/<table>?record=<record>` — and
139
+ NOTHING read the parameter. So an approval, an assignment, an agent's proposal
140
+ and (since 0.41.0) a checklist step all offered an Open that did not open
141
+ anything. Measured in the real app on a dental practice's onboarding steps.
142
+
143
+ `TablePage` takes `activeRecordId` and opens the record rail on it, moving the
144
+ rail when a later link names a different record. Absent, the page opens exactly
145
+ as it did. `openingRail` is the exported seam and `src/record-link.test.tsx`
146
+ fails on 0.43.0's bytes.
147
+
148
+ **Consumer action:** pass `activeRecordId` from your route's `?record=`
149
+ parameter, beside the `activeDashboardId` you already pass. Without it the Open
150
+ control in the inbox still goes nowhere.
151
+
3
152
  ## 0.43.0
4
153
 
5
154
  **Five headings carrying the store's real counts, over five empty columns.**