@ai-matrx/records-ui 0.30.0 → 0.38.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,260 @@
1
1
  # Changelog — @ai-matrx/records-ui
2
2
 
3
+
4
+
5
+ ## 0.38.0 — 2026-09-20
6
+
7
+ **0.37.0's gate went red on the tarball, not on this package.** The packed
8
+ consumer imports `@ai-matrx/records` from npm, and the published copy did not
9
+ yet carry `openCaptureQueue` — a door the offline capture screens here already
10
+ call. That is the tarball canary doing exactly its job: green in the monorepo,
11
+ absent for an npm consumer. `@ai-matrx/records` 0.26.0 carries it, and this
12
+ release is the first that can resolve against it.
13
+
14
+
15
+ ## 0.37.0 — 2026-09-20
16
+
17
+ **Three unhandled rejections were failing the release gate while every test
18
+ passed.** `demo/fixtures/doors.json` had no recorded answer for
19
+ `custom.enrich_cells`, a door the Enrich screens started calling — and the
20
+ recorded-doors fake deliberately REFUSES to invent one, because an empty answer
21
+ there would be a green test about nothing. That refusal arrived as an unhandled
22
+ rejection, so vitest reported `12 passed / 79 passed` and exited non-zero, and
23
+ 0.36.0 never reached npm. The fixtures are re-recorded against the live store;
24
+ the suite is now 12 files / 79 tests with no errors.
25
+
26
+
27
+ ## 0.37.0 — 2026-09-20
28
+
29
+ **The capture sheet, run on a phone, with or without a signal (PRODUCTS row 15).**
30
+
31
+ * `CaptureRun` — a DECLARED capture sheet, one question at a time, big targets,
32
+ the camera and the microphone through `accept`/`capture` (which is what opens
33
+ them on a phone rather than a file browser), and the durable queue from
34
+ `@ai-matrx/records@0.25.0` underneath. The whole sheet is fetched ONCE by
35
+ `custom.capture_open` and everything after that happens on the phone: a
36
+ validation that needs a round trip does not exist in a basement. It never says
37
+ *saved* when it means *queued* — the thank-you screen says which, the waiting
38
+ count is on screen the whole time, and "last synced" is a real moment read from
39
+ the queue. A member who may only look is told in words on the FIRST screen,
40
+ because `may_capture` comes from the door with a sentence attached.
41
+ * `CaptureSheet` gains `sheetId` and delegates to `CaptureRun` when it is given.
42
+ One component, two modes: with a sheet it runs what somebody DECLARED (the crew
43
+ case — twelve people, one round, the same questions); without one it stays the
44
+ ad-hoc capture that guesses which Field a reading goes in, which is right for a
45
+ one-off and wrong for a crew. No second capture component.
46
+
47
+ ## 0.36.0
48
+
49
+ **"Not between ten at night and seven in the morning" — the two settings the notify
50
+ editor could not offer, and the summary you can ask to see.**
51
+
52
+ `NotifyRuleEditor` could say WHICH view and, out of a two-word vocabulary, roughly
53
+ how often. There was no way to say "Monday at eight" and no way at all to say when
54
+ NOT to be told, so a subscription that texts on a new lead texted at 03:00. It now
55
+ asks for the cadence (from the store's own catalogue — a picker can never offer a
56
+ word the runner does not act on), the channel, the schedule, and both ends of a
57
+ quiet-hours block, and it says plainly that a send inside those hours is HELD until
58
+ they end rather than dropped.
59
+
60
+ It also stops assembling the Rule itself and writes through `subscriptionDeclare`.
61
+ The store is the one place that knows which cadences the runner honours and which
62
+ quiet hours it can parse, and it refuses the rest by name — so the sentence a person
63
+ reads on a refusal is the store's own.
64
+
65
+ `SubscriptionsPanel` gained the two answers anybody looking at a notifications list
66
+ actually wants: **when the next summary is due** (computed by the same store
67
+ functions the runner uses, so the screen and the runner cannot drift — and absent
68
+ rather than wrong on a muted subscription) and when it last told you anything. Plus
69
+ **"Send me a preview now"**, which renders the summary it would send at this moment
70
+ with what arrived, what left and what changed NAMED. It assembles only: nothing is
71
+ delivered, nothing is recorded and the watermark does not move, so pressing it never
72
+ costs somebody a text and never robs the real Monday summary of a week of news.
73
+
74
+ Needs `@ai-matrx/records` ≥ 0.26.0.
75
+
76
+
77
+ ## 0.36.0 — 2026-09-20
78
+
79
+ **0.35.0 never reached npm: the demo harness asked the store for ten thousand
80
+ rows in one page.**
81
+
82
+ `custom.read_records` serves at most a thousand rows in one page and now REFUSES
83
+ a bigger ask outright (`22023`, `PAGE-1`) rather than quietly serving fewer —
84
+ which is the right behaviour and exactly the kind of honesty this package is
85
+ built on. The harness's reset asked for 10,000, so it read nothing, threw, and
86
+ took the whole release gate down with it. It pages now, a thousand at a time,
87
+ until a short page says it is done. The ceiling is the store's to raise
88
+ (`custom/page_size_ceiling`); a caller's job is to page.
89
+
90
+ Proven against the LIVE store with the demo server up: `demo/live-smoke.test.tsx`
91
+ green, 1 passed.
92
+
93
+ Also in this release, from 0.34.0/0.35.0 and this lane:
94
+
95
+ - **"Who changed this?" is drawn for a person who cannot edit the cell.**
96
+ `columnForField` chose between the cell shell and a plain value on whether
97
+ there was an EDIT SESSION, and the grid passes `null` there whenever the table
98
+ is not this person's to write — so on a viewer, a portal and every read-only
99
+ embed the control vanished, while `gridEditing.tsx` promised it in its own
100
+ comments. `GridCell` now takes `editing: GridEditing | null`; a null session
101
+ means no editor, and nothing else.
102
+ - The tarball canary names `HistoryPanel`, `CommentThread` and
103
+ `FieldHistoryPanel`, so a screen that is green in the monorepo and absent from
104
+ an npm consumer's tarball is caught at the gate.
105
+
106
+
107
+ ## 0.35.0
108
+
109
+ **Per-record AI enrichment: the badge on every agent-owned cell, and the panel behind it.**
110
+
111
+ `EnrichBadge` is drawn beside every value a model owns, always — not on hover and
112
+ not behind a toggle, because a value a machine guessed and a value a person typed
113
+ are different facts and the difference has to survive onto the screen. Hovering it
114
+ gives the rest: who, when, what was read, how sure the model was, what it nearly
115
+ said instead, and the one control that matters — taking the cell back. `stale`
116
+ rides beside it as a second WORD rather than a colour, because "this is six weeks
117
+ old" is a sentence and a hue has to be explained every time.
118
+
119
+ `useEnrichCells` fetches a whole page's provenance in ONE `custom.enrich_cells`,
120
+ and `Grid` uses it for the ids it is actually drawing.
121
+
122
+ `EnrichPanel` is rewritten. It was a per-record "refill these fields" button over a
123
+ port nothing bound; it is now the whole of an enrichment in one screen, in the
124
+ order somebody thinks in: what should go in this column · what it may look at ·
125
+ how often to check it again · what it has cost, per run and per row · SEE IT ON
126
+ FIVE ROWS · and only then, turn it on. Setting one up from a column's own menu
127
+ lands here too, so "Let AI fill" is not a button that leads nowhere.
128
+
129
+ `TableSettings` gains that menu entry beside Edit and Remove, and marks a column a
130
+ model already fills in.
131
+
132
+ **BREAKING:** `EnrichPanel` no longer takes `recordId`. It is a panel about a
133
+ COLUMN and its whole Table, which is what "keep this filled in" is about; the old
134
+ signature could only ever refill one record.
135
+
136
+ The package's own gate now resolves `@ai-matrx/records` to the workspace SOURCE
137
+ rather than the last published tarball — before that, a suite could only exercise
138
+ doors already on npm, so every new door arrived untested through the one gate meant
139
+ to catch it.
140
+
141
+ ## 0.34.0
142
+ ## 0.33.0 — 2026-09-20
143
+
144
+ **"Who changed this?" rendered zero controls for the person most likely to ask
145
+ it.**
146
+
147
+ `gridEditing.tsx` says in its own comments that the cell's history control is
148
+ offered at VIEWER too — "a person who may not edit a cell is exactly the person
149
+ who wants to know who did". `columnForField` did not agree: it chose between the
150
+ cell shell and a plain value on whether there was an EDIT SESSION, and the grid
151
+ passes `null` there whenever the table is not this person's to write. So on a
152
+ viewer, a portal and every read-only embed the shell vanished and took the
153
+ control with it. The shell is now drawn whenever there is an editor OR a
154
+ question to ask, and `GridCell` takes `editing: GridEditing | null` — a null
155
+ session means no editor, and nothing else. `src/who-changed.test.tsx` covers
156
+ it; its load-bearing clause fails on the old gate.
157
+
158
+
159
+ ## 0.32.0
160
+
161
+ **The import wizard, rebuilt on the store's own import doors (SCR-10 / SCR-N-7).**
162
+
163
+ `ImportWizard` parsed a file and then called `recordWrite` **once per row**. At
164
+ the five thousand rows a real spreadsheet holds that is five thousand HTTP round
165
+ trips; there was no duplicate check, so importing a corrected file made a second
166
+ copy of everything; nothing recorded that a value came from a file; and a
167
+ refusal carried a row NUMBER into a file the screen no longer had, so "row 3,184
168
+ was refused" was information nobody could act on. `onProposeField` handed a
169
+ header to a callback and the platform forgot about it.
170
+
171
+ The bytes are still parsed here — Postgres cannot unzip a workbook — and
172
+ **everything after the parse is the store's**:
173
+
174
+ - **The plan, before anything is written.** `importPlan` answers what each
175
+ column is, reading the parity map AND this organization, and the screen shows
176
+ the kind, the store's own sentence saying why, and the first values. Every
177
+ column's destination is a dropdown a person can change, and what they change
178
+ is what the store is sent.
179
+ - **A duplicate key, chosen on the screen** ("same row means the same …"), with
180
+ "leave it alone" or "bring it up to date".
181
+ - **Batches of 250** through `importRows`, with a live count, and **one outcome
182
+ per row**: landed, already here, or refused **with the store's own sentence
183
+ and the row from the person's own file** beside it. The outcome table filters
184
+ to refused / already-here and is the click-through SCR-10 asks for.
185
+ - **The same file twice writes nothing.** The file's sha-256 is the run's
186
+ identity; the screen shows when it ran and what landed, and never sends a row.
187
+ Where Web Crypto is genuinely absent the screen SAYS it cannot recognise the
188
+ file again rather than inventing a hash.
189
+ - **Columns this table does not have go to the ONE approvals inbox** by default,
190
+ and the screen says so on the control itself. "Add them straight away" is
191
+ offered only to an admin and is **absent, not disabled,** for anybody else —
192
+ who are not stuck, because the default still files their column.
193
+ - **One word per type, everywhere.** The wizard reads `FIELD_TYPE_CHOICES`, the
194
+ same list the "Add field" panel offers, so a column is "Money" in both places.
195
+
196
+ `ImportWizardProps.onProposeField` is **gone**: the offer is now a real change
197
+ waiting in a real queue, not a callback the host had to invent a home for. Both
198
+ existing call sites (`TablesHome`, `TablePage`) already pass only `tableId` and
199
+ `onDone`.
200
+
201
+ New in the blocking gate: `src/import-wizard.test.tsx`, five clauses against
202
+ door answers recorded from the live store. Its red twin is `demo/import.red.tsx`
203
+ (the screen as it was), which fails on all three arms.
204
+
205
+ Requires `@ai-matrx/records` >= 0.19.0.
206
+ ## 0.31.0
207
+
208
+ **A record's past is a list of VERSIONS, and an agent names the person it acted for.**
209
+
210
+ `HistoryPanel` listed each field's LATEST value with the author of the last
211
+ write beside it. Useful, and not a history: it could not say what a price was
212
+ before, when it changed, what else changed with it, or put any of it back. It
213
+ reads `custom.record_history` now — one line per VERSION, newest first, each
214
+ naming who, when, the operation in the word somebody used, and every field that
215
+ moved with its before and its after, the Rule version that produced a derived
216
+ value and the evidence behind it. Keyboard-first: Up and Down walk the versions,
217
+ Enter opens one, R starts a restore.
218
+
219
+ **The put-it-back action names what will change before it does.** Pressing
220
+ Restore asks the store what the write would do and shows it — *"Price 1,100 →
221
+ 1,200, Notes cleared"* — and only the second press writes. It says out loud that
222
+ the write is a new version and nothing in the chain is erased, which is the
223
+ thing people are afraid of about an undo button.
224
+
225
+ **`FieldHistoryPanel` is new: "who changed this?", asked of a CELL.** Every grid
226
+ cell now carries the question (a quiet control on hover or focus, and `H` from
227
+ the keyboard at viewer too — a person who may not edit a cell is exactly the
228
+ person who wants to know who did), and the answer is that COLUMN's history
229
+ across the whole Table, with "put this one back" on each row.
230
+
231
+ **`CommentThread` stops keeping its own store.** It declared a package-owned
232
+ system Table called `records_ui_comment` into whichever organization opened the
233
+ screen — the same second store lane FORMS removed for forms and lane DASHBOARDS
234
+ removed for dashboards — and here the rung was wrong in BOTH directions: a
235
+ `commenter` could not comment at all, and anybody with write on the package's
236
+ comment Table could comment on a record they may not open. It reads
237
+ `custom.comment_thread` and writes `custom.comment_write` now, with the people
238
+ NAMED, a comment anchored to one Field, resolve and re-open, and an `@` mention
239
+ picked from the organization's own roster. Whether this person may comment is
240
+ the STORE'S answer, in the same call that answers the thread.
241
+
242
+ **Two defects the SCREENSHOTS found**, neither visible to a test, a type or a
243
+ door: a version's timestamp rendered `9/20/2026, 7:12:37 AM` and wrapped onto two
244
+ lines, doubling the height of every row — it is a relative time now (`12 minutes
245
+ ago`, `Tue 14:12`, then a date) with the exact moment on hover, which is what
246
+ Linear and Notion do and is also what fits. And the cell's "who changed this?"
247
+ control was `display:none` until hover, so it was unreachable by the keyboard
248
+ and invisible to anything driving the screen; it is `opacity-0` now and appears
249
+ on hover OR focus.
250
+
251
+ **Consumer action:** `COMMENT_TABLE` is gone — it described a store that no
252
+ longer exists and nothing outside this package used it. `HistoryPanel` gains an
253
+ optional `onAskAboutField`, `CommentThread` an optional `fieldKey`, and `Grid`,
254
+ `ViewSwitcher` and `columnForField` an optional `onAskWhoChanged`; every one is
255
+ additive and absent means the control is not drawn. Needs
256
+ `@ai-matrx/records` >= 0.18.0.
257
+
3
258
  ## 0.30.0
4
259
 
5
260
  **The notification editor stops asking for the notifier's own reader.**
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # @ai-matrx/records-ui
2
2
 
3
- THE canonical screens of the AI Matrx record store. Every component here reads
4
- and writes ONLY through [`@ai-matrx/records`](../records/README.md), renders
5
- with `@ai-matrx/design-system`'s own primitives and data table, and carries
3
+ The platform's primary record UI components. Every component here reads and
4
+ writes ONLY through [`@ai-matrx/records`](../records/README.md), renders with
5
+ `@ai-matrx/design-system`'s own primitives and data table, and carries
6
6
  `@ai-matrx/alchemy`'s menu where a person reaches for one.
7
7
 
8
8
  There is no bespoke per-feature record UI in this platform. A feature that needs