@ai-matrx/records 0.17.0 → 0.20.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,120 @@
1
1
  # Changelog — @ai-matrx/records
2
2
 
3
+
4
+ ## 0.20.0 — 2026-09-20
5
+
6
+ **The store moved and this package's census caught it — twice.** The release
7
+ gate runs the live-door suite against the real record store, and it went red on
8
+ main:
9
+
10
+ - `src/store.generated.ts` regenerated from the live store. The value envelope
11
+ gained `pinned`, the door census gained `conversation_scope` and its bind /
12
+ unbind / context siblings (478 doors, up from 428), and the knob list grew to
13
+ 43. Nothing in that file is typed by a person.
14
+ - **SQLSTATE `22003` is mapped.** `custom.context_resolve` raises it — a number
15
+ the store could not hold at the size it was handed — and this package did not
16
+ know the class, so it would have read as `internal` in somebody's console. It
17
+ is `invalid_argument`, the same class `22P02`, `42703` and `22007` already
18
+ are: the call named a value the shape does not accept, and the store's own
19
+ sentence names the number and the range.
20
+
21
+
22
+ ## 0.19.0
23
+
24
+ **"Pull my spreadsheet in" — the import doors, and the address a Table can own.**
25
+
26
+ `core/io.ts` has parsed CSV and XLSX bytes since W4-IO, and `ImportWizard` then
27
+ wrote the rows one at a time through `recordWrite` — one HTTP round trip per
28
+ row, no duplicate check, no provenance, and a refusal that carried a row NUMBER
29
+ into a file the screen no longer had. Every one of those is a way to lose data
30
+ quietly at 5,000 rows.
31
+
32
+ Eleven client methods arrive. The BYTES are still parsed here, because Postgres
33
+ cannot unzip a workbook; **everything after the parse is the store's**, so a file
34
+ imported from a screen, from an agent and from a script land identically and
35
+ there is no second importer in this package to drift.
36
+
37
+ - **`importPlan({ table_id, columns })`** — what the store makes of a file's
38
+ columns before anything is written, reading the parity map AND this
39
+ organization: an address that belongs to a member is a `member` column, a few
40
+ repeating words are a `select` with its options, `$1,250.00` is `currency` with
41
+ its unit, a column of names that are all records of another Table is a
42
+ `relation` at it. Every answer carries one sentence saying why, and two columns
43
+ that would make the same key say so.
44
+ - **`importBegin(...)`** — opens a run with the file's sha-256 as its IDENTITY.
45
+ The same bytes into the same table a second time answer the FIRST run with
46
+ `already: true` and write nothing, so **a re-import doubles nothing**. Carries
47
+ the duplicate key and the policy the whole run obeys.
48
+ - **`importRows({ import_id, rows, mapping })`** — a BATCH. Every row goes
49
+ through the one write door inside its own subtransaction and comes back with
50
+ one of exactly three outcomes: `landed` with the record id, `duplicate` with
51
+ the id of the record already there, or `refused` with the store's own sentence
52
+ **and the source row**, so an outcome table is clickable. Every value that
53
+ lands carries `{"kind":"import", …}` as its source (VAL-1).
54
+ - **`importFinish({ import_id, unmapped })`** — closes the run and sends every
55
+ column the file had and the table did not to the **ONE approvals inbox**
56
+ (`propose`, the default and the only choice a non-admin has), or adds them
57
+ outright (`create`, an admin's), or leaves them out. Never a junk bag.
58
+ - **`importReport`**, **`imports`**, **`importForget`** — the refused and
59
+ already-here rows with their source, this organization's runs, and forgetting
60
+ a receipt so the same bytes can be imported again deliberately.
61
+ - **`inboundDeclare` / `inboundAddresses` / `inboundSet`** (DOOR-19) — the
62
+ address a Table owns. `inboundDeclare` answers with **`mail_route`**: the one
63
+ sentence saying what has to exist in DNS before anything arrives. Show it
64
+ wherever the address is shown. The gateway's own landing door is deliberately
65
+ absent from this client — it is `service_role`'s alone.
66
+
67
+ New types in `@ai-matrx/records`: `ImportPlan`, `ImportColumnPlan`,
68
+ `ImportPolicy`, `ImportOpened`, `ImportOutcome`, `ImportProposal`,
69
+ `ImportBatchResult`, `ImportFinished`, `ImportReport`, `ImportRun`,
70
+ `InboundAddress`, `InboundDeclared`.
71
+
72
+ `store.generated.ts` regenerated against the live store: **428 doors**.
73
+
74
+ ## 0.18.0
75
+
76
+ **"Who changed this price, and can I put it back?" — the doors for PRODUCTS row 4.**
77
+
78
+ The store has kept every version of every record since W3-HIST: one append-only
79
+ chain covering Values AND structure, with the compound verb that wrote each
80
+ version stamped on it since MERGE-HISTORY. None of it reached a screen. The only
81
+ thing a client could ask for was `revisions()` (`custom.io_revisions`), which
82
+ answers a version number, a moment, a RAW UUID for the author and a list of
83
+ KEYS — so a timeline could say "something changed" and could not say who, what
84
+ it was before, or which Rule produced a derived value.
85
+
86
+ Seven client methods arrive:
87
+
88
+ - **`recordHistory({ record_id })`** — one record's versions, newest first, each
89
+ naming the author as `user` / `agent` / `system` **and, for an agent, the
90
+ person it acted for**, the operation in the word somebody used, and every
91
+ field that moved with its `before`, its `after`, the Rule VERSION that
92
+ produced a derived value and its interned source pointer. Viewer.
93
+ - **`fieldHistory({ table_id, field_key })`** — one column's history across a
94
+ whole Table ("who changed the price on ANY record"), narrowed to the records
95
+ this person may see by a predicate in the same statement. A column that names
96
+ no Field is refused BY NAME.
97
+ - **`restorePreview({ record_id, version, field_key? })`** — what a restore
98
+ would change, BEFORE it does, computed by the body that computes the write.
99
+ Editor: the first half of an act is not shown to somebody who may not do it.
100
+ - **`restoreVersion`** and **`valueRestore`** — put the whole record, or ONE
101
+ column (HIS-N-2), back to what it said at a version. Both write a NEW version
102
+ through the record's own write path; no stored version is ever altered.
103
+ - **`commentThread`**, **`commentWrite`**, **`commentResolve`** — SCR-18, at the
104
+ store's own `commenter` rung, with everybody NAMED, a comment anchored to one
105
+ Field, and a mention that notifies the person named.
106
+
107
+ **Consumer action:** none required. `revisions()` is unchanged and every
108
+ existing caller keeps working. A screen showing a record's past should move to
109
+ `recordHistory` — `revisions()` cannot answer who, and was never able to.
110
+
111
+ **And two defects in the store this came with**, both fixed in the same session
112
+ and both reaching every existing caller: `custom.io_restore` did not restore (it
113
+ patched the old document through a merging write, so a key added after the
114
+ target version survived its own restore in silence), and it returned NULL to
115
+ every caller it has ever had (it read the version out of the read door, which
116
+ answers a document, and `version` is a column).
117
+
3
118
  ## 0.17.0
4
119
 
5
120
  **A list is a door, never a grant on the thing behind it.**