@ai-matrx/records 0.53.0 → 0.55.1

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,79 @@
1
1
  # Changelog — @ai-matrx/records
2
2
 
3
+ ## 0.55.1
4
+
5
+ **0.55.0, actually published.** The tag `npm/records/v0.55.0` never reached the registry: its
6
+ publish gate failed on `pnpm typecheck` (OLD-TABLES-2's relation-words suite had four type
7
+ errors vitest never reads) and then on two `real-doors` clauses that still asserted the record
8
+ store OFF after STORE-ON's owner ruling made it ON by default. Both are fixed in the suites; no
9
+ runtime byte differs from what 0.55.0 describes below. The version moved rather than the tag
10
+ because a published tag is never rewritten. (lane PUBLISH-SWEEP-4.)
11
+
12
+ ## 0.55.0
13
+
14
+ **Three things that were already in the source and had never reached a consumer.** (published
15
+ by lane PUBLISH-SWEEP-4; built by STORE-TXN, OLD-TABLES-2 and ORG-CLEANUP-2, each of which
16
+ landed its work marked "source only, not published".)
17
+
18
+ * **`recordWriteGraph`** — the typed client over `custom.record_write_graph` (lane STORE-TXN).
19
+ A parent, the edges it stands on and the rows that belong to it in ONE transaction, with one
20
+ op id for the whole graph. `recordWrite` and `recordWriteMany` are each one statement, so a
21
+ caller needing a parent and its children to land together had no door: a loop is N
22
+ transactions and a failure on child nineteen leaves a parent standing without the lines it
23
+ promised. Not a second write path — the door calls `custom.record_write_many`,
24
+ `public.assoc_add` and `platform.relation_set`, so every guard and trigger runs once as
25
+ before. `RecordGraphWritten` counts the two edge writers apart (`edge_ids` / `relations`)
26
+ instead of making a caller subtract.
27
+ * **`relationWordsMany` dispatches by store** (lane OLD-TABLES-2). A relation cell holds an id
28
+ and a screen shows words, and there are two stores holding such cells: `custom.record` and
29
+ the pre-doctrine `workbench.udt_*` tables, where most people's data actually sits. ONE client
30
+ primitive now reads both, discriminated by an optional `store` — and **a caller that names
31
+ none reaches exactly the door and the arguments it reached before**, so the thirteen live
32
+ screens on `custom._words_for` change not one line. The older arm goes to
33
+ `workbench.udt_row_words_many` through `WORKBENCH_DOORS` / `WORKBENCH_SCHEMA`, named by hand
34
+ for the same reason `TRUST_DOORS` is (`records:generate` reads `custom` and only `custom`).
35
+ The arms are asymmetric on purpose: the unified arm takes the FIELD because that is where the
36
+ display spec is declared and judged; the older store has no declare-time judge, so its arm
37
+ carries the spec. An id the door answered nothing for stays ABSENT from the map either way —
38
+ inventing "Untitled" would erase the difference between a cell pointing at nothing and a row
39
+ that was refused. New types: `RelationStore`, `RelationDisplaySpec`, `RelationWordsManyArgs`.
40
+ * **The `throwaway` placeholder pattern** (lane ORG-CLEANUP-2) — after 48 organizations named
41
+ "Throwaway Dash 3fee58c2" walked back onto the owner's organization picker overnight and
42
+ `PLACEHOLDER_PATTERNS` could not see one of them: 28 of the 48 carried no `zz` at all. It
43
+ now catches "throwaway", "disposable org", "safe to delete" and "test only", and mirrors
44
+ `iam.placeholder_in_a_name` on the platform database — a pattern added to one belongs in the
45
+ other.
46
+
47
+ Also regenerated `store.generated.ts`, which was stale (`real-doors.test.ts` was red on main
48
+ claiming `record_write_graph` absent while it exists). Proof: `src/__tests__/relation-words-by-store.test.ts`
49
+ goes RED on 3 of 5 clauses with one line of the dispatch reversed. Suite at publish: 105/105
50
+ across 9 files.
51
+
52
+ ## 0.54.0
53
+
54
+ **A formula can be re-aimed through a typed door.** (lane STORE-TAILS-2's ask, published by
55
+ PUBLISH-SWEEP-2.)
56
+
57
+ `custom.field_update` has carried `expr` in its behaviour arm since lane TAILS-2 — its spec
58
+ builder reads `coalesce(p_patch -> 'expr', v_old -> 'config' -> 'expr')` — but `FieldPatch`
59
+ never named the key. So the one edit a person makes to a formula that reads the wrong
60
+ column, re-aiming it, had no typed door in this package, and the client that needed it
61
+ reached for `custom.record_update` on the Field document instead: writing a column's
62
+ definition UNDER the store's guards rather than through them.
63
+
64
+ * `FieldPatch.expr?: Record<string, unknown>` — the expression in the same shape a Rule
65
+ uses and read by the same evaluator. It belongs to the door's BEHAVIOUR arm, so it is
66
+ sent WITH the word for what the column is (`type: "formula"`, or `parity_type` / `plain`);
67
+ the settings arm has no `expr` key, so `expr` alone is not a change this door makes. The
68
+ interface says so rather than leaving a caller to find out from silence.
69
+ * Guard: `src/__tests__/real-doors.test.ts` — "`expr` on a FieldPatch moves the expression;
70
+ a re-type without one keeps it", live against the main store inside the suite's
71
+ rollback-only transaction. Both halves are asserted, because "the expression is X
72
+ afterwards" would pass on a door that ignored the patch. Every `{"field": …}` names the
73
+ column BY ITS ID, which is what `custom._field_type_parity_guard` requires — a key is "a
74
+ name rather than a column". Shown RED (the re-aimed expression still held the title
75
+ column's id) then GREEN. Suite: 100/100.
76
+
3
77
  ## 0.53.0
4
78
 
5
79
  **Archiving a table is a job, not a statement.** (lane FIX-11A, VERIFIER-11 finding F3.)
@@ -1145,6 +1145,7 @@ var STORE_DOORS = [
1145
1145
  { name: "doors_not_deciding_the_record", args: "", returns: "TABLE(function_name text, identity_args text, why text)", security: "invoker" },
1146
1146
  { name: "doors_not_masking_fields", args: "", returns: "TABLE(function_name text, identity_args text, why text)", security: "invoker" },
1147
1147
  { name: "doors_not_on_one_ladder", args: "", returns: "TABLE(function_name text, identity_args text, why text)", security: "invoker" },
1148
+ { name: "doors_refusing_in_another_doors_name", args: "", returns: "TABLE(function_name text, identity_args text, why text)", security: "invoker" },
1148
1149
  { name: "effective_level", args: "p_user_id uuid, p_organization_id uuid, p_id uuid, p_type text DEFAULT 'record'::text", returns: "permission_level", security: "definer" },
1149
1150
  { name: "enrich_cells", args: "p_organization_id uuid, p_table_id uuid, p_field_keys text[] DEFAULT NULL::text[], p_record_ids uuid[] DEFAULT NULL::uuid[]", returns: "TABLE(record_id uuid, field_key text, agent_owned boolean, value jsonb, value_version integer, actor text, on_behalf_of text, written_at timestamp with time zone, source jsonb, absent_reason text, alternates jsonb, pinned boolean, stale boolean, due_at timestamp with time zone)", security: "definer" },
1150
1151
  { name: "enrich_declare", args: "p_organization_id uuid, p_field_id uuid, p_spec jsonb", returns: "jsonb", security: "definer" },
@@ -1187,6 +1188,7 @@ var STORE_DOORS = [
1187
1188
  { name: "field_rules", args: "p_field_data jsonb", returns: "TABLE(kind text, spec jsonb)", security: "invoker" },
1188
1189
  { name: "field_update", args: "p_organization_id uuid, p_field_id uuid, p_patch jsonb", returns: "uuid", security: "definer" },
1189
1190
  { name: "field_value_convert", args: "p_to jsonb, p_value jsonb", returns: "jsonb", security: "invoker" },
1191
+ { name: "field_words", args: "p_organization_id uuid, p_field_id uuid, p_value jsonb", returns: "text", security: "invoker" },
1190
1192
  { name: "file_kernel_id", args: "", returns: "uuid", security: "invoker" },
1191
1193
  { name: "form_declare", args: "p_organization_id uuid, p_table_id uuid, p_title text, p_questions jsonb, p_presentation jsonb DEFAULT '{}'::jsonb, p_submission_cap integer DEFAULT NULL::integer, p_quarantine_rule_id uuid DEFAULT NULL::uuid, p_notify_rule_id uuid DEFAULT NULL::uuid, p_form_id uuid DEFAULT NULL::uuid, p_slug text DEFAULT NULL::text", returns: "uuid", security: "definer" },
1192
1194
  { name: "form_notify", args: "p_organization_id uuid, p_form_id uuid, p_record_id uuid, p_submission_id uuid", returns: "uuid", security: "invoker" },
@@ -1278,6 +1280,7 @@ var STORE_DOORS = [
1278
1280
  { name: "migrate_merge", args: "p_organization_id uuid, p_winner_id uuid, p_loser_id uuid, p_note text DEFAULT NULL::text", returns: "jsonb", security: "definer" },
1279
1281
  { name: "migrate_promote", args: "p_organization_id uuid, p_table_id uuid, p_note text DEFAULT NULL::text", returns: "jsonb", security: "definer" },
1280
1282
  { name: "migrate_purge", args: "p_organization_id uuid, p_table_id uuid DEFAULT NULL::uuid, p_dry_run boolean DEFAULT true", returns: "jsonb", security: "definer" },
1283
+ { name: "migrate_purge_hard", args: "p_organization_id uuid, p_table_id uuid DEFAULT NULL::uuid, p_compliance_reason text DEFAULT NULL::text, p_chunk integer DEFAULT 200, p_dry_run boolean DEFAULT true", returns: "jsonb", security: "definer" },
1281
1284
  { name: "migrate_reclass", args: "p_organization_id uuid, p_id uuid, p_to text DEFAULT 'field'::text, p_note text DEFAULT NULL::text", returns: "jsonb", security: "definer" },
1282
1285
  { name: "migrate_rename", args: "p_organization_id uuid, p_id uuid, p_to text, p_note text DEFAULT NULL::text", returns: "jsonb", security: "definer" },
1283
1286
  { name: "migrate_reparent", args: "p_organization_id uuid, p_id uuid, p_parent_id uuid, p_note text DEFAULT NULL::text", returns: "jsonb", security: "definer" },
@@ -1405,6 +1408,7 @@ var STORE_DOORS = [
1405
1408
  { name: "record_values_versioned", args: "p_organization_id uuid, p_record_id uuid", returns: "TABLE(field_key text, field_id uuid, value jsonb, value_version integer, source jsonb, absent_reason text, actor text, on_behalf_of text, written_at timestamp with time zone, alternates jsonb)", security: "definer" },
1406
1409
  { name: "record_words", args: "p_organization_id uuid, p_record_id uuid, p_noun text DEFAULT NULL::text", returns: "text", security: "definer" },
1407
1410
  { name: "record_write", args: "p_organization_id uuid, p_table_id uuid, p_data jsonb", returns: "uuid", security: "definer" },
1411
+ { name: "record_write_graph", args: "p_organization_id uuid, p_table_id uuid, p_parent jsonb, p_edges jsonb DEFAULT '[]'::jsonb, p_children jsonb DEFAULT '[]'::jsonb", returns: "jsonb", security: "definer" },
1408
1412
  { name: "record_write_many", args: "p_organization_id uuid, p_table_id uuid, p_rows jsonb[], p_ids uuid[] DEFAULT NULL::uuid[]", returns: "uuid[]", security: "definer" },
1409
1413
  { name: "refusals_claiming_a_level_never_asked", args: "", returns: "TABLE(function_name text, identity_args text, why text)", security: "invoker" },
1410
1414
  { name: "relation_carry", args: "p_organization_id uuid, p_container_id uuid, p_item_id uuid", returns: "uuid", security: "definer" },
@@ -1483,6 +1487,7 @@ var STORE_DOORS = [
1483
1487
  { name: "table_declare", args: "p_organization_id uuid, p_spec jsonb", returns: "uuid", security: "definer" },
1484
1488
  { name: "table_has_a_visible_record", args: "p_user uuid, p_organization_id uuid, p_table_id uuid", returns: "boolean", security: "definer" },
1485
1489
  { name: "table_is_live", args: "p_organization_id uuid, p_table_id uuid", returns: "boolean", security: "invoker" },
1490
+ { name: "table_is_options_table", args: "p_organization_id uuid, p_table_id uuid", returns: "boolean", security: "invoker" },
1486
1491
  { name: "table_kernel_id", args: "", returns: "uuid", security: "invoker" },
1487
1492
  { name: "table_record_ceiling", args: "", returns: "integer", security: "invoker" },
1488
1493
  { name: "table_record_ceiling", args: "p_organization_id uuid", returns: "integer", security: "invoker" },
@@ -1496,6 +1501,8 @@ var STORE_DOORS = [
1496
1501
  { name: "table_stage_field", args: "p_organization_id uuid, p_table_id uuid", returns: "text", security: "definer" },
1497
1502
  { name: "table_storage", args: "p_organization_id uuid, p_table_id uuid", returns: "text", security: "invoker" },
1498
1503
  { name: "table_type_field", args: "p_organization_id uuid, p_table_id uuid", returns: "text", security: "definer" },
1504
+ { name: "table_unique_rule_fields", args: "p_organization_id uuid, p_table_id uuid", returns: "jsonb", security: "invoker" },
1505
+ { name: "table_work_kind", args: "p_organization_id uuid, p_table_id uuid", returns: "text", security: "invoker" },
1499
1506
  { name: "tables_at_home", args: "p_organization_id uuid, p_home_ids uuid[]", returns: "TABLE(table_id uuid, home_record_id uuid, kind text)", security: "definer" },
1500
1507
  { name: "tables_described_without_asking", args: "", returns: "TABLE(function_name text, identity_args text, why text)", security: "invoker" },
1501
1508
  { name: "trg_associations_bump_visibility", args: "", returns: "trigger", security: "definer" },
@@ -1611,15 +1618,15 @@ var STORE_REFUSAL_CODES = [
1611
1618
  { code: "02000", raised_by: "_checklist_instantiate,_portal_invite_payload,_share_write_person,_table_share_invite_payload,checklist_declare,checklist_run,checklist_step_complete,checklist_step_refusal,checklist_template_shape,conversation_scope_bind,dashboard_delete,dashboard_run,doc_letterhead,doc_render_body,doc_render_document,doc_render_read,doc_sign,doc_signature_intact,doc_signature_read,doc_template_delete,doc_template_read,doc_template_save,enrich_pin,entity_field_retire,entity_field_update,entity_record_read,entity_value_write,external_history_event,external_rows,external_stub_upsert,external_writes_set,io_restore,migrate_delete,migrate_extract_parent,migrate_merge,migrate_reclass,migrate_rename,migrate_reparent,migrate_retype,migrate_split,migrate_undo,organization_clear,portal_archive,portal_card,portal_declare,portal_invite,portal_invite_accept,portal_preview,portal_principal_bind,portal_restore,portal_revoke,read_record,record_delete,record_restore,record_restore_preview,record_table,record_update,relation_uncarry,share_access,share_grant,share_lane_set,share_people,share_revoke,sign_request_cancel,sign_request_create,sign_request_remind,sign_request_unchanged,table_archive,table_share_outside_accept,table_share_outside_invite,table_share_outside_resend,table_share_outside_revoke,visibility_as_of,work_approval_decide,work_approval_read,work_approval_request,work_assign,work_record_states,work_set_state" },
1612
1619
  { code: "0A000", raised_by: "checklist_step_complete,external_rows,external_source_declare,external_write_through,promote_field,promoted_index_expr,promoted_query_sql,promoted_read,rule_eval,work_assign" },
1613
1620
  { code: "22003", raised_by: "context_resolve" },
1614
- { code: "22004", raised_by: "_entity_custom_fields_guard,_share_write_person,_value_envelope,actor_word,agg_assert_key,agg_sql,anon_capture,anon_token_issue,anon_write,assert_client_may_reach,booking_declare,capture_submit,checklist_declare,context_resolve,dashboard_block_normalize,dashboard_declare,dashboard_window_sql,doc_render_write,doc_sign,doc_signature_write,doc_template_save,enrich_land,enrich_normalize,external_history_event,external_rows,external_source_declare,external_stub_upsert,external_write_through,external_writes_set,field_history,form_declare,form_submit,home_add,io_comment_write,io_import_begin,io_infer_column,io_outbox_drain,io_restore,migrate_choice_keys,migrate_purge,migrate_reclass,migrate_split,migrate_undo,organization_clear,organization_contents,pipeline_declare,pipeline_gate_preview,portal_declare,portal_invite,portal_principal_bind,provenance_retention_days,provenance_write,query_across_homes,query_by_coordinates,query_rollup,record_delete,record_reparent,record_resolve,record_restore,record_update,record_write,record_write_many,relation_carry,relation_own,rule_declare,share_grant,sign_request_create,sign_request_sign,subscription_declare,table_archive,table_declare,table_share_outside_invite,value_restore,view_declare,work_approval_decide,work_approval_request,work_template_declare" },
1621
+ { code: "22004", raised_by: "_entity_custom_fields_guard,_share_write_person,_value_envelope,actor_word,agg_assert_key,agg_sql,anon_capture,anon_token_issue,anon_write,assert_client_may_reach,booking_declare,capture_submit,checklist_declare,context_resolve,dashboard_block_normalize,dashboard_declare,dashboard_window_sql,doc_render_write,doc_sign,doc_signature_write,doc_template_save,enrich_land,enrich_normalize,external_history_event,external_rows,external_source_declare,external_stub_upsert,external_write_through,external_writes_set,field_history,form_declare,form_submit,home_add,io_comment_write,io_import_begin,io_infer_column,io_outbox_drain,io_restore,migrate_choice_keys,migrate_purge,migrate_purge_hard,migrate_reclass,migrate_split,migrate_undo,organization_clear,organization_contents,pipeline_declare,pipeline_gate_preview,portal_declare,portal_invite,portal_principal_bind,provenance_retention_days,provenance_write,query_across_homes,query_by_coordinates,query_rollup,record_delete,record_reparent,record_resolve,record_restore,record_update,record_write,record_write_graph,record_write_many,relation_carry,relation_own,rule_declare,share_grant,sign_request_create,sign_request_sign,subscription_declare,table_archive,table_declare,table_share_outside_invite,value_restore,view_declare,work_approval_decide,work_approval_request,work_template_declare" },
1615
1622
  { code: "22007", raised_by: "dashboard_window_sql" },
1616
1623
  { code: "22012", raised_by: "rule_eval" },
1617
- { code: "22023", raised_by: "_booking_availability,_entity_custom_fields_guard,_take_op_id,_value_envelope,_work_shape_guard,actor_word,agg_assert_key,agg_sql,anon_token_issue,booking_declare,containment_parent,dashboard_block_normalize,dashboard_window_sql,doc_render_body,doc_render_write,doc_signature_write,enrich_declare,enrich_land,enrich_normalize,enrich_pin,entity_value_write,external_history_event,external_source_declare,external_stub_upsert,external_write_through,field_history,field_update,io_export,io_import_begin,io_import_finish,io_import_plan,io_import_report,io_proposal_accept,list_portals,migrate_merge,migrate_reclass,my_levels,organization_clear,page_size,pin_agent_cells,pipeline_move,portal_declare,provenance_write,query_by_coordinates,query_rollup,read_records_archived,record_update,record_write_many,relation_carry,rule_eval,rule_members,share_grant,share_lane_set,sign_request_create,sign_request_sign,subscription_declare,table_rules,visibility_as_of,work_approval_request,work_list,work_slot_hold" },
1624
+ { code: "22023", raised_by: "_booking_availability,_entity_custom_fields_guard,_take_op_id,_value_envelope,_work_shape_guard,actor_word,agg_assert_key,agg_sql,anon_token_issue,booking_declare,containment_parent,dashboard_block_normalize,dashboard_window_sql,doc_render_body,doc_render_write,doc_signature_write,enrich_declare,enrich_land,enrich_normalize,enrich_pin,entity_value_write,external_history_event,external_source_declare,external_stub_upsert,external_write_through,field_history,field_update,io_export,io_import_begin,io_import_finish,io_import_plan,io_import_report,io_proposal_accept,list_portals,migrate_merge,migrate_reclass,my_levels,organization_clear,page_size,pin_agent_cells,pipeline_move,portal_declare,provenance_write,query_by_coordinates,query_rollup,read_records_archived,record_update,record_write_graph,record_write_many,relation_carry,rule_eval,rule_members,share_grant,share_lane_set,sign_request_create,sign_request_sign,subscription_declare,table_rules,visibility_as_of,work_approval_request,work_list,work_slot_hold" },
1618
1625
  { code: "23503", raised_by: "_booking_availability,_checklist_instantiate,_containment_guard,_display_spec_for,_field_document_for,_field_type_parity_guard,_pipeline_stage_key,_record_rule_uses,agg_digest_assemble,anon_publish,anon_rate_take,anon_token_issue,anon_write,assert_organization_wall,booking_cancel,booking_confirm,booking_declare,booking_hold,booking_reschedule,capture_publish,checklist_declare,checklist_steps_table,comment_write,dashboard_declare,delete_rule,doc_sign,doc_template_save,enrich_declare,enrich_due,enrich_land,form_declare,form_submit,home_add,inbound_declare,inbound_mail_land,inbound_set,io_comment_write,io_import_begin,io_import_finish,io_import_report,io_import_rows,io_proposal_accept,migrate_demote,migrate_promote,pipeline_board,pipeline_declare,pipeline_move,pipeline_read,pipeline_transition_refusal,promote_field,promote_table,record_applicability,record_reparent,relation_carry,relation_own,resolve_first_match,rule_applies,rule_declare,rule_eval,rule_members,rule_run,sign_request_create,subscription_mute,subscription_preview,view_declare,work_set_state,work_take_assignment,work_template_instantiate" },
1619
1626
  { code: "23505", raised_by: "_share_write_person,_unique_rule_holds,doc_sign,doc_signature_write,entity_field_declare,field_declare,home_add,inbound_declare,io_proposal_accept,relation_carry,relation_own,sign_request_cancel,sign_request_create,table_share_outside_resend,work_approval_decide,work_slot_hold" },
1620
- { code: "23514", raised_by: "_checklist_instantiate,_checklist_step_guard,_containment_guard,_dated_values_guard,_derived_fields,_display_spec_for,_entity_custom_fields_guard,_field_class_guard,_field_document_for,_field_shape_guard,_field_type_parity_guard,_merge_field_shape_guard,_merge_field_temporal_guard,_promoted_field_cap_guard,_record_rule_uses,_resolve_choice_words,_rule_shape_guard,_rule_topology_guard,_store_relation_edge_names_its_field,_table_columns_word_guard,_table_shape_guard,_undeclared_key_guard,_value_envelope,_with_display,_work_shape_guard,_workdoors_approval_guard,assert_columns_are_defined,assert_entity_is_organization_scoped,booking_declare,capture_publish,capture_sheet_declare,checklist_declare,checklist_step_complete,doc_sign,doc_signature_write,doc_template_save,entity_field_declare,entity_field_retire,entity_field_update,entity_records_find,entity_table,field_declare,field_retire,field_update,home_add,io_comment_write,io_import_rows,migrate_merge,portal_archive,portal_restore,relation_carry,relation_own,sign_request_create,sign_request_sign,table_declare,validate_value_envelope,validate_values,work_set_state,work_slots_declare,work_take_assignment,work_template_instantiate" },
1627
+ { code: "23514", raised_by: "_checklist_instantiate,_checklist_step_guard,_containment_guard,_dated_values_guard,_derived_fields,_display_spec_for,_entity_custom_fields_guard,_field_class_guard,_field_document_for,_field_shape_guard,_field_type_parity_guard,_merge_field_shape_guard,_merge_field_temporal_guard,_promoted_field_cap_guard,_record_rule_uses,_relation_halves_agree,_resolve_choice_words,_rule_shape_guard,_rule_topology_guard,_store_relation_edge_names_its_field,_table_columns_word_guard,_table_shape_guard,_undeclared_key_guard,_value_envelope,_with_display,_work_shape_guard,_workdoors_approval_guard,assert_columns_are_defined,assert_entity_is_organization_scoped,booking_declare,capture_publish,capture_sheet_declare,checklist_declare,checklist_step_complete,doc_sign,doc_signature_write,doc_template_save,entity_field_declare,entity_field_retire,entity_field_update,entity_records_find,entity_table,field_declare,field_retire,field_update,home_add,io_comment_write,io_import_rows,migrate_merge,migrate_purge_hard,portal_archive,portal_restore,record_write_graph,relation_carry,relation_own,sign_request_create,sign_request_sign,table_declare,validate_value_envelope,validate_values,work_set_state,work_slots_declare,work_take_assignment,work_template_instantiate" },
1621
1628
  { code: "40001", raised_by: "has_visibility_at" },
1622
- { code: "42501", raised_by: "_doc_render_immutable,_doc_signature_immutable,_field_definition_write,_field_write_door,_rule_definition_write,_store_door,agent_table_claim,anon_capture,anon_inbound_land,anon_publish,anon_token_issue,anon_token_verify,anon_write,assert_client_may_change,assert_client_may_open,assert_client_may_reach,assert_may_know_table,assert_organization_admin,assert_store_door,booking_confirm,booking_declare,booking_hold,capture_submit,checklist_run,comment_write,conversation_scope_bind,conversation_scope_unbind,doc_sign,enrich_declare,enrich_due,enrich_land,enrich_normalize,entity_field_declare,entity_field_retire,entity_field_update,entity_value_write,external_write_through,form_declare,form_submit,inbound_mail_land,io_comment_resolve,io_comment_write,io_import_begin,io_import_finish,io_restore,migrate_purge,migrate_reclass,my_levels,organization_clear,portal_declare,portal_invitation,portal_invite,portal_invite_accept,portal_principal_bind,promote_table,query_visibility_parity,read_record,read_records,read_records_archived,read_records_by_ids,read_records_matching,record_table,share_grant,subscription_mute,subscription_preview,table_share_outside_accept,table_share_outside_invite,table_share_outside_resend,visibility_as_of,work_approval_decide,work_approval_read,work_approval_request,work_person" },
1629
+ { code: "42501", raised_by: "_doc_render_immutable,_doc_signature_immutable,_field_definition_write,_field_write_door,_rule_definition_write,_store_door,agent_table_claim,anon_capture,anon_inbound_land,anon_publish,anon_token_issue,anon_token_verify,anon_write,assert_client_may_change,assert_client_may_open,assert_client_may_reach,assert_may_know_table,assert_organization_admin,assert_store_door,booking_confirm,booking_declare,booking_hold,capture_submit,checklist_run,comment_write,conversation_scope_bind,conversation_scope_unbind,doc_sign,enrich_declare,enrich_due,enrich_land,enrich_normalize,entity_field_declare,entity_field_retire,entity_field_update,entity_value_write,external_write_through,form_declare,form_submit,inbound_mail_land,io_comment_resolve,io_comment_write,io_import_begin,io_import_finish,io_restore,migrate_purge,migrate_purge_hard,migrate_reclass,my_levels,organization_clear,portal_declare,portal_invitation,portal_invite,portal_invite_accept,portal_principal_bind,promote_table,query_visibility_parity,read_record,read_records,read_records_archived,read_records_by_ids,read_records_matching,record_table,record_write_graph,share_grant,subscription_mute,subscription_preview,table_share_outside_accept,table_share_outside_invite,table_share_outside_resend,visibility_as_of,work_approval_decide,work_approval_read,work_approval_request,work_person" },
1623
1630
  { code: "42703", raised_by: "entity_table,portal_declare" },
1624
1631
  { code: "53400", raised_by: "anon_rate_take,delete_cascade_closure,enrich_due,enrich_land,promote_field" },
1625
1632
  { code: "54001", raised_by: "record_delete" },
@@ -2688,6 +2695,18 @@ var TRUST_DOORS = {
2688
2695
  worldPublishAdmit: "world_publish_admit",
2689
2696
  claimWorldNamespace: "claim_world_namespace"
2690
2697
  };
2698
+ var WORKBENCH_SCHEMA = "workbench";
2699
+ var WORKBENCH_DOORS = {
2700
+ /**
2701
+ * What a page of the OLDER store's relation cells reads, in one round trip.
2702
+ * Same answer shape as `custom.relation_words_many`, same withheld sentence,
2703
+ * and the ladder is asked per record inside it — so batching buys a round
2704
+ * trip and never a disclosure. An id that names nothing comes back as
2705
+ * NOTHING rather than as the withheld sentence, which is what makes an
2706
+ * unresolvable cell distinguishable from a refused one in that store.
2707
+ */
2708
+ udtRowWordsMany: "udt_row_words_many"
2709
+ };
2691
2710
  var DOOR_NAMES = new Set(STORE_DOORS.map((d) => d.name));
2692
2711
  function doorExists(name) {
2693
2712
  return DOOR_NAMES.has(name);
@@ -2740,6 +2759,17 @@ var DOORS = {
2740
2759
  queryTableAsOf: "query_table_as_of",
2741
2760
  recordWrite: "record_write",
2742
2761
  recordWriteMany: "record_write_many",
2762
+ // A PARENT, THE EDGES IT STANDS ON AND THE ROWS THAT BELONG TO IT — ALL OR NOTHING.
2763
+ // `recordWrite` and `recordWriteMany` are each ONE statement, so a caller that needs a
2764
+ // parent, its provenance edge and its child rows to land together had no door at all: a
2765
+ // loop is N transactions, and a failure on child nineteen leaves a parent standing without
2766
+ // the lines it promised. `custom.record_write_graph` is one statement, so it is one
2767
+ // transaction — and it is not a second write path: it CALLS `custom.record_write_many` for
2768
+ // the rows, `public.assoc_add` for an edge that points out of the store, and
2769
+ // `platform.relation_set` for the parent's own declared relation to its children. Every
2770
+ // guard, every trigger and the same editor rung, once. A refusal anywhere refuses the whole
2771
+ // graph, by name, and nothing is written.
2772
+ recordWriteGraph: "record_write_graph",
2743
2773
  recordUpdate: "record_update",
2744
2774
  recordDelete: "record_delete",
2745
2775
  recordRestore: "record_restore",
@@ -3362,6 +3392,15 @@ function createRecordsClient(config) {
3362
3392
  }
3363
3393
  return ok(response.data);
3364
3394
  }
3395
+ async function workbenchDoor(door, args, where) {
3396
+ const response = await config.dataSource.rpc(door, args, { schema: WORKBENCH_SCHEMA });
3397
+ if (response.error) {
3398
+ const refusal = mapPgError(response.error, where);
3399
+ scream({ code: refusal.code, message: refusal.message, ...refusal.hint ? { hint: refusal.hint } : {}, where });
3400
+ return err(refusal);
3401
+ }
3402
+ return ok(response.data);
3403
+ }
3365
3404
  function unfold(document) {
3366
3405
  const raw = document ?? {};
3367
3406
  const hidden = raw._hidden ?? {};
@@ -3401,6 +3440,25 @@ function createRecordsClient(config) {
3401
3440
  "recordWriteMany"
3402
3441
  );
3403
3442
  },
3443
+ async recordWriteGraph({ table_id, parent, children, edges }) {
3444
+ const opId = mintOpId();
3445
+ return callDoor(
3446
+ DOORS.recordWriteGraph,
3447
+ {
3448
+ p_organization_id: org,
3449
+ p_table_id: table_id,
3450
+ p_parent: { ...parent, _op_id: opId },
3451
+ p_edges: edges ?? [],
3452
+ p_children: (children ?? []).map((child) => ({
3453
+ data: child.data,
3454
+ role: child.role,
3455
+ ...child.table_id === void 0 ? {} : { table_id: child.table_id },
3456
+ ...child.position === void 0 ? {} : { position: child.position }
3457
+ }))
3458
+ },
3459
+ "recordWriteGraph"
3460
+ );
3461
+ },
3404
3462
  async recordUpdate({ record_id, patch, expectedVersion }) {
3405
3463
  const result = await callDoor(
3406
3464
  DOORS.recordUpdate,
@@ -3786,16 +3844,26 @@ function createRecordsClient(config) {
3786
3844
  "relationWords"
3787
3845
  );
3788
3846
  },
3789
- async relationWordsMany({ field_id, record_ids }) {
3790
- const result = await callDoor(
3847
+ async relationWordsMany(args) {
3848
+ const older = args.store === "older";
3849
+ const result = older ? await workbenchDoor(
3850
+ WORKBENCH_DOORS.udtRowWordsMany,
3851
+ {
3852
+ p_organization_id: org,
3853
+ p_display: args.display ?? null,
3854
+ p_row_ids: args.record_ids
3855
+ },
3856
+ "relationWordsMany(older)"
3857
+ ) : await callDoor(
3791
3858
  DOORS.relationWordsMany,
3792
- { p_organization_id: org, p_field_id: field_id, p_record_ids: record_ids },
3859
+ { p_organization_id: org, p_field_id: args.field_id, p_record_ids: args.record_ids },
3793
3860
  "relationWordsMany"
3794
3861
  );
3795
3862
  if (!result.ok) return result;
3796
3863
  const map = {};
3797
3864
  for (const row of result.data ?? []) {
3798
- if (row?.record_id && typeof row.words === "string") map[row.record_id] = row.words;
3865
+ const id = row?.record_id ?? row?.row_id;
3866
+ if (id && typeof row.words === "string") map[id] = row.words;
3799
3867
  }
3800
3868
  return { ok: true, data: map };
3801
3869
  },