@ai-matrx/records 0.58.9 → 0.58.12

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,12 +1,59 @@
1
1
  # Changelog — @ai-matrx/records
2
2
 
3
+ ## 0.58.12 (2026-09-25)
4
+
5
+ ### Lane DECLARE-ENTITY-REF (2026-09-25)
6
+
7
+ * **Every column word reaches the door as `type`.** `declareTable` / `addFields` / `fieldDeclarationFor`
8
+ mapped `text` / `long_text` / `number` synonyms to `plain` and sent EVERY other word as
9
+ `parity_type` — but `custom._field_document_for` accepts `parity_type` only for the fourteen parity
10
+ types, while its `type` arm resolves them all. So eight words were refused ("There is no field type
11
+ called …"): `entity_reference`, `relation`, `signature`, `autonumber`, `created_time`,
12
+ `modified_time`, `list`, `boolean`. The word is now sent as `type`, unmapped (multiline text still
13
+ becomes `long_text`), and `NewFieldSpec.allowedTypes` carries an entity reference's kinds as
14
+ `allowed_types`. Guard: `every-declarable-word-reaches-the-door-as-its-word.test.ts` holds the
15
+ door's rule against every word it resolves. Proven live: a table with an
16
+ `entity_reference → ai_model` column declared as admin, a record written with
17
+ `{token: "ai_model", id}`, one `platform.associations` row answered.
18
+ **Consumer action:** a caller that put `allowed_types` in `config` may keep it (the door reads both)
19
+ or move it to `allowedTypes`; nothing else changes.
20
+
21
+ ## 0.58.11 (2026-09-25 — published by PUBLISH-SWEEP-6)
22
+
23
+ 0.58.10 was tagged but never reached npm: its publish gate (`real-doors.test.ts`, "no signed-out caller
24
+ reaches the store") counted `custom._older_table_copy_refusal(uuid)`, an anonymous door lane
25
+ WHERE-LIVES-SWITCH declared in `platform.client_callable_door`. The gate now counts only UNDECLARED
26
+ anon grants and also asserts anon holds no USAGE on schema `custom`. Everything under 0.58.10 below
27
+ ships here.
28
+
29
+ ## 0.58.10 (2026-09-25 — tagged by PUBLISH-SWEEP-5; never published, see 0.58.11)
30
+
31
+ Carries S5-PRIME-2's decision hold (`WorkInboxItem.undo_seconds` / `undo_refusal`, `3e2c93da3c`; registry
32
+ 689 doors), which records-ui 0.85.12 reads, so it publishes first. ORDER-FILTER shipped in 0.58.9 (below).
33
+
34
+ ### Lane MOVER-BIG-VALUES (2026-09-25)
35
+
36
+ * **A value kept as a file** (`core/wholeValue.ts`): a value over the organization's ceiling for one
37
+ value is kept as a file and the cell holds its first 1000 characters, its envelope pointing at a
38
+ `whole_value_in_file` provenance entry. `wholeValueOf(document, key)` / `wholeValueOfRead(value)`
39
+ recognise it; `withWholeValues(rows, readFileText)` makes an export write the file's whole content;
40
+ `cellText` never passes the words off as the whole value (it says where the rest is).
41
+
42
+ ### Lane S5-PRIME-2, VERIFIER-20 (2026-09-25)
43
+
44
+ * **`WorkInboxItem.undo_seconds` / `undo_refusal`** (uichamp_s5c, applied to production
45
+ 2026-09-25): how long a decision on the row is held with Undo — the organization's
46
+ `custom/decision_undo_seconds` (default 5) for a pending approval or proposal, 0 with the store's
47
+ sentence when a run already waits on the answer, null for work and closed rows. Registry
48
+ regenerated (689 doors).
49
+
3
50
  ## 0.58.9
4
51
 
5
52
  Automatic changed-only republish (docs/metadata drift since the last tag — see
6
53
  `git diff npm/records/v0.58.8..npm/records/v0.58.9 -- apps/shared/records`).
7
54
  No source changes intended and no consumer action required.
8
55
 
9
- ## Unreleased — lane ORDER-FILTER (2026-09-25)
56
+ ### Lane ORDER-FILTER (2026-09-25)
10
57
 
11
58
  * **The order door takes the view's filter.** `readInViewOrder({ view_id, filter, limit, offset })`
12
59
  now takes `filter` (`StoreFilter`: the flat map or a nested Rule — the view's own `where`, or a
@@ -2247,6 +2247,7 @@ __export(core_exports, {
2247
2247
  TABLE_TYPES: () => TABLE_TYPES,
2248
2248
  VALUE_ALTERNATE_KEYS: () => VALUE_ALTERNATE_KEYS,
2249
2249
  VALUE_ENVELOPE_KEYS: () => VALUE_ENVELOPE_KEYS,
2250
+ WHOLE_VALUE_SOURCE_KIND: () => WHOLE_VALUE_SOURCE_KIND,
2250
2251
  actionRefusals: () => actionRefusals,
2251
2252
  addFields: () => addFields,
2252
2253
  allowsOtherValues: () => allowsOtherValues,
@@ -2343,9 +2344,14 @@ __export(core_exports, {
2343
2344
  supabaseDataSource: () => supabaseDataSource,
2344
2345
  toAoa: () => toAoa,
2345
2346
  tokenFor: () => tokenFor,
2347
+ wholeValueNotRead: () => wholeValueNotRead,
2348
+ wholeValueOf: () => wholeValueOf,
2349
+ wholeValueOfRead: () => wholeValueOfRead,
2350
+ wholeValueSize: () => wholeValueSize,
2346
2351
  withRowCounts: () => withRowCounts,
2347
2352
  withTableFacts: () => withTableFacts,
2348
- withTablePlacement: () => withTablePlacement
2353
+ withTablePlacement: () => withTablePlacement,
2354
+ withWholeValues: () => withWholeValues
2349
2355
  });
2350
2356
  module.exports = __toCommonJS(core_exports);
2351
2357
 
@@ -4401,7 +4407,7 @@ var STORE_DOORS = [
4401
4407
  { name: "work_assignment_fields", args: "p_options_table_id uuid DEFAULT NULL::uuid", returns: "TABLE(key text, label text, spec jsonb)", security: "invoker" },
4402
4408
  { name: "work_decide_many", args: "p_organization_id uuid, p_decisions jsonb", returns: "jsonb", security: "definer" },
4403
4409
  { name: "work_has_assignment", args: "p_organization_id uuid, p_table_id uuid", returns: "boolean", security: "definer" },
4404
- { name: "work_inbox", args: "p_organization_id uuid, p_limit integer DEFAULT 50, p_offset integer DEFAULT 0, p_include_decided boolean DEFAULT false, p_view text DEFAULT 'inbox'::text", returns: "TABLE(item_id uuid, kind text, origin text, title text, subject_id uuid, subject_kind text, summary text, state text, due_on timestamp with time zone, due_state text, actionable boolean, requested_by uuid, requested_by_name text, at timestamp with time zone, table_id uuid, table_name text, decided_by uuid, decided_by_name text, decided_at timestamp with time zone, outcome text, snoozed_until timestamp with time zone, cleared_at timestamp with time zone, snoozed_count integer, cleared_count integer)", security: "definer" },
4410
+ { name: "work_inbox", args: "p_organization_id uuid, p_limit integer DEFAULT 50, p_offset integer DEFAULT 0, p_include_decided boolean DEFAULT false, p_view text DEFAULT 'inbox'::text", returns: "TABLE(item_id uuid, kind text, origin text, title text, subject_id uuid, subject_kind text, summary text, state text, due_on timestamp with time zone, due_state text, actionable boolean, requested_by uuid, requested_by_name text, at timestamp with time zone, table_id uuid, table_name text, decided_by uuid, decided_by_name text, decided_at timestamp with time zone, outcome text, snoozed_until timestamp with time zone, cleared_at timestamp with time zone, snoozed_count integer, cleared_count integer, undo_seconds integer, undo_refusal text)", security: "definer" },
4405
4411
  { name: "work_instantiation_shape", args: "p_organization_id uuid, p_instantiation_id uuid", returns: "jsonb", security: "definer" },
4406
4412
  { name: "work_list", args: "p_organization_id uuid, p_flavour text DEFAULT 'mine'::text, p_include_finished boolean DEFAULT false, p_limit integer DEFAULT 100, p_offset integer DEFAULT 0", returns: "TABLE(record_id uuid, table_id uuid, table_name text, title text, assignee_id uuid, assignee_name text, assignee_user_id uuid, due_on timestamp with time zone, due_state text, status text, terminal boolean, assigned_by uuid, updated_at timestamp with time zone)", security: "definer" },
4407
4413
  { name: "work_person", args: "p_organization_id uuid, p_user_id uuid, p_create boolean DEFAULT true", returns: "uuid", security: "definer" },
@@ -4445,6 +4451,7 @@ var STORE_KNOBS = [
4445
4451
  { key: "containment_depth_ceiling", value: "16", type: "integer" },
4446
4452
  { key: "context_copy_following", value: "true", type: "boolean" },
4447
4453
  { key: "cross_organization_links", value: "false", type: "boolean" },
4454
+ { key: "decision_undo_seconds", value: "5", type: "integer" },
4448
4455
  { key: "decoration_rules_max", value: "50", type: "integer" },
4449
4456
  { key: "decorations_max_bytes", value: "262144", type: "integer" },
4450
4457
  { key: "document_letterhead", value: "{}", type: "json" },
@@ -8552,7 +8559,8 @@ function fieldDeclarationFor(field) {
8552
8559
  ...field.options ? { options: field.options } : {},
8553
8560
  ...field.relationTarget ? { relation_target: field.relationTarget } : {},
8554
8561
  ...field.unit ? { unit: field.unit } : {},
8555
- ...field.kind ? { kind: field.kind } : {}
8562
+ ...field.kind ? { kind: field.kind } : {},
8563
+ ...field.allowedTypes ? { allowed_types: field.allowedTypes } : {}
8556
8564
  };
8557
8565
  }
8558
8566
  async function declareTable(client, spec) {
@@ -8619,25 +8627,12 @@ async function addFields(client, tableId, fields) {
8619
8627
  }
8620
8628
  return { ok: true, data: tableId };
8621
8629
  }
8622
- var PLAIN_WORDS = {
8623
- text: "text",
8624
- string: "text",
8625
- long_text: "long_text",
8626
- longtext: "long_text",
8627
- paragraph: "long_text",
8628
- number: "number",
8629
- range: "number",
8630
- integer: "number",
8631
- decimal: "number",
8632
- float: "number"
8633
- };
8634
8630
  function declaredType(field) {
8635
8631
  const word = (field.type ?? "text").toLowerCase();
8636
- const plain = PLAIN_WORDS[word];
8637
- if (plain) {
8638
- return { plain: plain === "text" && field.config?.["multiline"] === true ? "long_text" : plain };
8632
+ if ((word === "text" || word === "string") && field.config?.["multiline"] === true) {
8633
+ return { type: "long_text" };
8639
8634
  }
8640
- return { parity_type: word };
8635
+ return { type: word };
8641
8636
  }
8642
8637
 
8643
8638
  // src/core/supabase.ts
@@ -9032,6 +9027,57 @@ function predictWriteRefusals(args) {
9032
9027
  return found;
9033
9028
  }
9034
9029
 
9030
+ // src/core/wholeValue.ts
9031
+ var WHOLE_VALUE_SOURCE_KIND = "whole_value_in_file";
9032
+ function asPointer(source) {
9033
+ if (!source || typeof source !== "object") return null;
9034
+ const s = source;
9035
+ if (s.kind !== WHOLE_VALUE_SOURCE_KIND || typeof s.file_id !== "string" || !s.file_id) return null;
9036
+ return s;
9037
+ }
9038
+ function wholeValueOf(document, key) {
9039
+ if (!document) return null;
9040
+ const envelope = (document._values ?? {})[key];
9041
+ const pointer = envelope?.src;
9042
+ if (typeof pointer !== "string") return null;
9043
+ return asPointer((document._sources ?? {})[pointer]);
9044
+ }
9045
+ function wholeValueOfRead(value) {
9046
+ return asPointer(value?.source ?? null);
9047
+ }
9048
+ function wholeValueSize(pointer) {
9049
+ const kb = pointer.bytes / 1024;
9050
+ return kb >= 1024 ? `${(kb / 1024).toFixed(1)} MB` : `${Math.round(kb)} KB`;
9051
+ }
9052
+ function wholeValueNotRead(words, pointer, why) {
9053
+ return `${words}\u2026 [This is the start of a ${wholeValueSize(pointer)} text kept as file ${pointer.file_id}` + (why ? `; it could not be read for this export: ${why}` : "") + "]";
9054
+ }
9055
+ async function withWholeValues(rows, read) {
9056
+ const texts = /* @__PURE__ */ new Map();
9057
+ const out = [];
9058
+ for (const row of rows) {
9059
+ const next = { ...row };
9060
+ for (const [key, value] of Object.entries(row)) {
9061
+ const pointer = wholeValueOfRead(value);
9062
+ if (!pointer || !value) continue;
9063
+ const words = typeof value.value === "string" ? value.value : "";
9064
+ if (!read) {
9065
+ next[key] = { ...value, value: wholeValueNotRead(words, pointer, "this screen has no way to read files"), source: null };
9066
+ continue;
9067
+ }
9068
+ if (!texts.has(pointer.file_id)) texts.set(pointer.file_id, read(pointer.file_id));
9069
+ try {
9070
+ next[key] = { ...value, value: await texts.get(pointer.file_id), source: null };
9071
+ } catch (thrown) {
9072
+ const why = thrown instanceof Error ? thrown.message : String(thrown);
9073
+ next[key] = { ...value, value: wholeValueNotRead(words, pointer, why), source: null };
9074
+ }
9075
+ }
9076
+ out.push(next);
9077
+ }
9078
+ return out;
9079
+ }
9080
+
9035
9081
  // src/core/io.ts
9036
9082
  var escape = (value) => /[",\n\r]/.test(value) ? `"${value.replace(/"/g, '""')}"` : value;
9037
9083
  function cellText(value) {
@@ -9039,6 +9085,8 @@ function cellText(value) {
9039
9085
  if (value.absent_reason) return `(${value.absent_reason})`;
9040
9086
  const raw = value.value;
9041
9087
  if (raw === null || raw === void 0) return "";
9088
+ const pointer = wholeValueOfRead(value);
9089
+ if (pointer && typeof raw === "string") return wholeValueNotRead(raw, pointer);
9042
9090
  if (typeof raw === "string") return raw;
9043
9091
  return JSON.stringify(raw);
9044
9092
  }