import { RecordsClient, RecordsSeed } from '@ai-matrx/records/core'; declare const ACTOR_VOCABULARY: readonly ["user", "agent", "system"]; declare const STORAGE_MODES: readonly ["light", "heavy"]; /** FLD-11's parity floor, each with the behavior it is MADE OF (FLD-1). */ declare const PARITY_FIELD_TYPES: readonly [{ readonly parity_type: "attachment"; readonly behavior: "relation"; readonly made_of: "REC-31: a File record reached through a relation, target the kernel `File` Table"; }, { readonly parity_type: "checkbox"; readonly behavior: "boolean"; readonly made_of: "a ticked or unticked answer, stored as a REAL boolean — and a record that never answered holds neither, so filters and group-by see three states, not two"; }, { readonly parity_type: "currency"; readonly behavior: "range"; readonly made_of: "FLD-N-1: a number whose UNIT is the currency and whose format is currency — on the Field, never in presentation"; }, { readonly parity_type: "datetime"; readonly behavior: "range"; readonly made_of: "a range of kind date or datetime — the dated modifier says the VALUES are dated, which is a different question"; }, { readonly parity_type: "email"; readonly behavior: "text"; readonly made_of: "text whose format is email"; }, { readonly parity_type: "formula"; readonly behavior: "formula"; readonly made_of: "FLD-9: a declared computation, on read or on write, evaluated by custom.rule_eval"; }, { readonly parity_type: "lookup"; readonly behavior: "formula"; readonly made_of: "a Value read THROUGH a relation — config.via names the relation field, config.pick the Value on the far side"; }, { readonly parity_type: "member"; readonly behavior: "relation"; readonly made_of: "a person: a relation whose target is the kernel `Person` Table"; }, { readonly parity_type: "multi_select"; readonly behavior: "list"; readonly made_of: "many choices from the same Table — the multi modifier, never a second behaviour"; }, { readonly parity_type: "percent"; readonly behavior: "range"; readonly made_of: "a number whose unit is % and whose format is percent"; }, { readonly parity_type: "phone"; readonly behavior: "text"; readonly made_of: "text whose format is phone"; }, { readonly parity_type: "rollup"; readonly behavior: "formula"; readonly made_of: "an aggregate ALONG a relation — config.via, config.of, config.agg; far-side ids are taken DISTINCT, so nothing is counted twice"; }, { readonly parity_type: "select"; readonly behavior: "list"; readonly made_of: "one choice from a Table shown as a list (FLD-5/FLD-6)"; }, { readonly parity_type: "url"; readonly behavior: "text"; readonly made_of: "text whose format is url, with the pattern Rule that makes the format enforceable"; }]; /** The node kinds `custom.rule_eval` evaluates, and the lane that owns each. */ declare const RULE_NODE_KINDS: readonly [{ readonly node: "actor_at_least"; readonly evaluated_by: "PIPELINES"; }, { readonly node: "add"; readonly evaluated_by: "W1-RULE"; }, { readonly node: "and"; readonly evaluated_by: "W1-RULE"; }, { readonly node: "concat"; readonly evaluated_by: "W1-RULE"; }, { readonly node: "const"; readonly evaluated_by: "W1-RULE"; }, { readonly node: "contains"; readonly evaluated_by: "NOTION-Q"; }, { readonly node: "div"; readonly evaluated_by: "W1-RULE"; }, { readonly node: "eq"; readonly evaluated_by: "W1-RULE"; }, { readonly node: "field"; readonly evaluated_by: "W1-RULE"; }, { readonly node: "fx.abs"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.add"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.and"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.arraycompact"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.arrayflatten"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.arrayjoin"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.arrayslice"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.arrayunique"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.at"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.autonumber"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.average"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.blank"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.ceiling"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.concatenate"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.contains"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.count"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.counta"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.countall"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.created_time"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.current"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.current1"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.current2"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.dateadd"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.datediff"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.datestr"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.datetime_diff"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.datetime_format"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.datetime_parse"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.day"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.div"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.encode_url_component"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.eq"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.error"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.even"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.every"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.exp"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.false"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.filter"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.find"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.findfirst"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.first"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.floor"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.fromnow"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.gt"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.gte"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.hour"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.if"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.includes"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.index"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.int"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.is_after"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.is_before"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.is_same"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.isblank"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.iserror"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.join"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.last"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.last_modified_time"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.left"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.len"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.length"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.log"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.lower"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.lt"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.lte"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.map"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.max"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.median"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.mid"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.min"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.minute"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.mod"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.modified_time"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.month"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.mul"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.ne"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.neg"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.not"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.now"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.odd"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.or"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.power"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.record_id"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.recprop"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.regex_extract"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.regex_match"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.regex_replace"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.regexreplace"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.replace"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.rept"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.reverse"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.right"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.round"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.rounddown"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.roundup"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.search"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.second"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.set_locale"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.set_timezone"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.slice"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.some"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.sort"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.split"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.sqrt"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.sub"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.substitute"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.sum"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.switch"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.t"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.timestr"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.today"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.tonow"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.trim"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.true"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.unique"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.upper"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.value"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.weekday"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.weeknum"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.workday"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.workday_diff"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.xor"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "fx.year"; readonly evaluated_by: "GRID-PRIMITIVES G3 (custom.formula_eval)"; }, { readonly node: "gt"; readonly evaluated_by: "W1-RULE"; }, { readonly node: "gte"; readonly evaluated_by: "W1-RULE"; }, { readonly node: "has_all"; readonly evaluated_by: "NOTION-Q"; }, { readonly node: "has_any"; readonly evaluated_by: "NOTION-Q"; }, { readonly node: "has_none"; readonly evaluated_by: "NOTION-Q"; }, { readonly node: "is_empty"; readonly evaluated_by: "NOTION-Q"; }, { readonly node: "is_exactly"; readonly evaluated_by: "NOTION-Q"; }, { readonly node: "is_not_empty"; readonly evaluated_by: "NOTION-Q"; }, { readonly node: "length"; readonly evaluated_by: "W1-RULE"; }, { readonly node: "linked"; readonly evaluated_by: "NOTION-Q"; }, { readonly node: "lt"; readonly evaluated_by: "W1-RULE"; }, { readonly node: "lte"; readonly evaluated_by: "W1-RULE"; }, { readonly node: "matches"; readonly evaluated_by: "W1-RULE"; }, { readonly node: "merge_field"; readonly evaluated_by: "W5-MERGE-B"; }, { readonly node: "mul"; readonly evaluated_by: "W1-RULE"; }, { readonly node: "ne"; readonly evaluated_by: "W1-RULE"; }, { readonly node: "not"; readonly evaluated_by: "W1-RULE"; }, { readonly node: "not_contains"; readonly evaluated_by: "NOTION-Q"; }, { readonly node: "or"; readonly evaluated_by: "W1-RULE"; }, { readonly node: "parent_field"; readonly evaluated_by: "W1-RULE-APPLY"; }, { readonly node: "present"; readonly evaluated_by: "W1-RULE"; }, { readonly node: "previous"; readonly evaluated_by: "PIPELINES"; }, { readonly node: "sibling_count"; readonly evaluated_by: "STAGE-RULES"; }, { readonly node: "stage_count"; readonly evaluated_by: "PIPELINES"; }, { readonly node: "sub"; readonly evaluated_by: "W1-RULE"; }, { readonly node: "within"; readonly evaluated_by: "CHAIR-FILTER"; }]; /** * VAL-8. Who wrote a value. `user`, `agent`, `system` — enforced by every write * door, and the three retired words (`human`, `ai`, `code`) are translated by * the store's own `custom.actor_word`, never by a caller. */ type Actor = (typeof ACTOR_VOCABULARY)[number]; /** * REC-4. `heavy` is indexed storage with Rules on write; `light` is * whole-document storage with Rules on read. Per Table, one store. */ type StorageMode = (typeof STORAGE_MODES)[number]; /** FLD-1. The five behaviors a Field can have. One, exactly, and closed. */ type FieldBehavior = (typeof PARITY_FIELD_TYPES)[number]["behavior"]; /** The node kinds `custom.rule_eval` evaluates. */ type RuleNodeKind = (typeof RULE_NODE_KINDS)[number]["node"]; /** * REC-32. The seven table types, closed. The parenthesised names are the * retired ones the doctrine records; never coin an eighth. */ declare const TABLE_TYPES: readonly ["entity", "detail", "reference", "ledger", "restricted", "system", "deprecated"]; type TableType = (typeof TABLE_TYPES)[number]; /** REL-2. What happens to the far side, separate from flavour. */ declare const ON_DELETE: readonly ["cascade", "set_null", "restrict"]; type OnDelete = (typeof ON_DELETE)[number]; /** FLD-7. Where a Field's values come from. */ declare const FIELD_SOURCES: readonly ["manual", "formula", "agent", "synced"]; type FieldSource = (typeof FIELD_SOURCES)[number]; /** FLD-9. A Formula declares whether it computes on read or on write. */ declare const COMPUTE_ON: readonly ["read", "write"]; type ComputeOn = (typeof COMPUTE_ON)[number]; /** * AGT-7 / FLD-12. A Field's sensitivity sets a ceiling a merge field can never * widen — and these are THE STORE'S four words, checked against its own guard. * * This list used to read `standard · sensitive · secret`, which the store has * never accepted: writing a Field with `sensitivity: "standard"` is refused * with "the field has to say how sensitive its values are, and it says * standard". The knob `custom/field_sensitivity_levels` keys off these same * four words to decide which level may read and edit each one, so a package * carrying three different words could never have agreed with it. Corrected * against the live store, 2026-09-18. */ declare const FIELD_SENSITIVITIES: readonly ["public", "internal", "confidential", "restricted"]; type FieldSensitivity = (typeof FIELD_SENSITIVITIES)[number]; /** * FLD-12. WHETHER AN AGENT MAY SEE A FIELD'S VALUES, and these are the STORE'S * four words — not the merge field's delivery tiers. * * `Field.context_policy` used to be typed as `Delivery` here, which is a * different question with a different vocabulary: writing a Field with * `context_policy: "inline"` is refused with "the field has to say * whether an agent may see its values, and it says inline". Delivery is about * HOW MUCH of a value a merge field carries into a turn; this is about WHETHER * the value reaches an agent at all, and conflating them let a screen offer a * word the store has never accepted. Corrected against the live store, * 2026-09-18. */ declare const CONTEXT_POLICIES: readonly ["include", "summarize", "exclude", "on_request"]; type ContextPolicy = (typeof CONTEXT_POLICIES)[number]; /** REC-1. How a Table shows itself. */ declare const TABLE_DISPLAYS: readonly ["list", "grid", "board", "calendar", "timeline"]; type TableDisplay = (typeof TABLE_DISPLAYS)[number]; /** * The structural shape of a PostgREST failure as supabase-js resolves it: a * PLAIN OBJECT parsed from the response body, NOT an `Error`. Reading * `.message` off `instanceof Error` discards the real database message on every * genuine failure. */ interface PgError { code?: string | null; message: string; details?: string | null; hint?: string | null; } /** A `uuid` as the store writes it. */ type Uuid = string; /** An ISO-8601 timestamp, as jsonb carries it. */ type Timestamp = string; /** * DOOR-SPEED. One key of a page's order, as `custom.read_records_page` takes it. `as` is the * column's own type — `number` sorts numerically (text that is not a number sorts last), * `date` sorts ISO dates and instants, `text` (the default) sorts by lower-cased text. A choice * column always sorts by the WORD a person sees; the store knows which columns are choices. * NULLS LAST both ways, record id as the tie-breaker. */ interface RecordPageSort { field: string; direction?: "asc" | "desc"; as?: "text" | "number" | "date"; } /** * A rule expression as `custom.rule_eval` ACTUALLY evaluates it — read off the * door's own body, not invented here. A leaf is the node's name carrying its * payload (`{"const": 3}`, `{"field": ""}`); an operator is * `{"op": "eq", "args": [...]}`. * * `field` / `parent_field` name a Field BY ID (REC-17 — the door refuses * `field_name`, `field_key` and `field_label` by name), and `merge_field` is * the resolver's seam, storable today and refused `0A000` until W5-MERGE-B. * * `p_values` is keyed by the Field's KEY: the door resolves the id to a key * (`custom.rule_field_key`) and then reads `p_values -> key`. */ type RuleExpression = { const: unknown; } | { field: Uuid; } | { parent_field: Uuid; } | { merge_field: string; } | { op: RuleNodeKind; args: RuleExpression[]; }; /** The measures the store offers. Asked of `custom.agg_operations()` at run time too. */ type AggregateOperation = "count" | "sum" | "avg" | "min" | "max" /** GRID-PRIMITIVES G1: the summary bar's other four. Blank = no value, JSON null or "". */ | "median" | "filled" | "empty" | "unique" /** * Notion's calculation row (Spaces N6): the share of the rows asked with no value / a value, as a * percent 0..100 (NULL over no rows); and the RANGE, largest minus smallest (a date column: the days * between its earliest and latest moment). */ | "percent_empty" | "percent_filled" | "range"; /** * A HALF-OPEN MOMENT WINDOW: `from` is inclusive, `to` is exclusive. Half-open * is the only shape that makes "September" and "October" meet exactly once — * an inclusive `to` either double-counts the boundary moment or drops it, * depending on the reader, and both of those are a chart telling a lie. */ interface AggregateWindow { from?: string | null; to?: string | null; } /** * ONE FILTER VALUE, as `custom.record_aggregate` and `custom.dashboard_run` * both read it: a SCALAR is an equality, and an OBJECT is a window. It is not * `unknown` on purpose — a filter value the store cannot read is a refusal a * caller should get from the compiler, not from the database. */ type AggregateFilter = string | number | boolean | null | AggregateWindow; /** * 🚨 THE STORE'S ONE FILTER SHAPE, AND THE ONLY NAME FOR IT. * * An object of Field key -> value. A scalar is an equality, `null` is UNSET * (the third state of a tick box), an object is a half-open time window. * * It is not the aggregate's private shape and never was. `platform.saved_view` * has carried exactly this as `definition -> 'filters'` across five live * surface keys since DOOR-18; `custom.view_declare` writes it; * `custom.agg_view_admits` reads it to decide whether a change belongs to a * saved view; `custom.record_aggregate` takes it as `p_filter` to COMPUTE a * dashboard number; and `custom.read_records_matching` takes it to OPEN the * rows behind that number. One `custom.record_filter_sql` in the database turns * it into SQL for the last two, so the number and the rows cannot disagree. * * Invent a second one and a chart can compute a total whose drill-through * lands somewhere else, which is the only way a drill-through can lie. */ type RecordFilter = Record; /** * S2-PRIME FILTER-GROUPS — A READ DOOR'S QUESTION, IN EITHER OF ITS TWO SHAPES. * * The flat `RecordFilter` above (field key → scalar / `null` / window, AND only) is what * dashboards, drill-throughs and the notifier carry. A `RuleExpression` — `{op, args}`, ALL / ANY / * NOT groups nested to any depth, fields by id — is what the condition builder, a view's own * filter and every membership Rule speak. `custom.record_filter_sql(org, table, filter)` turns * EITHER into the one WHERE clause the grid (`list`), the aggregate and the board all use, so the * three can never disagree about which records a view holds. */ type StoreFilter = RecordFilter | RuleExpression; /** One measure. `count` counts rows and needs no Field; the rest read one. */ interface AggregateMeasure { op: AggregateOperation; /** The Field's key. Required for every operation except `count`. */ key?: string; } /** FLD-3. A constraint attached to a Field. A Rule, never a behavior. */ interface FieldRule { /** * `unique` (FLD-3 / B1): no two live records of the Table hold the same value, compared * case- and outer-space-blind. The store enforces it under an advisory lock * (`custom._unique_rule_holds`); it is also what lets `recordUpsert` find "the" record by a key. * The mirror never predicts it — it needs a query. */ kind: "min" | "max" | "length" | "pattern" | "equals_field" | "differs_from_field" | "unique"; /** * The rule's own number or word: the least / the most for `min` / `max`, the * LONGEST for `length`, the pattern for `pattern`, the other column's key for * `equals_field` / `differs_from_field`. A `length` rule that only says how * SHORT a value may be carries `min` and no `value`. */ value?: string | number; /** * STORE-RULE-GAPS (the older grid's `patternHint`). On a `pattern` rule only: * how a person writes it, e.g. `"949-555-0142"`. The store refuses an example * its own pattern would refuse, and a refused value is told "Enter it like * 949-555-0142." (the hint, and `detail.example`). */ example?: string; /** * STORE-RULE-GAPS (the older grid's `minLength`). On a `length` rule only: the * fewest characters. A blank is `required`'s question, never "too short". */ min?: number; /** FLD-10. Empty means "wherever the Field applies". */ applies_to_types?: string[]; } /** * `custom.field` — the ONE definitions table (FLD-8), organization-scoped, so * two organizations add different fields to the same standard table. */ /** * WHICH OF THE OTHER RECORD'S COLUMNS A RELATION SHOWS (REL-DISP, 2026-09-21). * * A Table has ONE stored default reference column — its `title_field` — and until * this existed every relation pointing at that Table could display that column and * nothing else. A Jobs board could read "Maria Chen" but never "Maria Chen — * Rincon", and two columns could not be joined into one string at all. * * ABSENT MEANS THE TABLE'S OWN COLUMN. A field with no `display` resolves exactly * as it did before, so nothing changes for a column nobody has given a spec to. * * The store judges it once, in `custom._display_spec_for`: every column named must * exist on the target Table, and the refusal names the one that does not. It is * resolved by ONE body, `custom._words_for`, which `custom.record_words`, * `custom._card_words`, `custom.relation_words` and `custom.relation_words_many` * are all one-liners onto — so the thirteen store-side readers inherit it too. * * A display column that is itself a relation resolves ONE hop and never a second. */ interface RelationDisplay { /** The target's columns, in the order they are shown. */ columns: string[]; /** What goes between them. Defaults to a single space. */ separator: string; } interface Field { id: Uuid; organization_id: Uuid; /** Set when this Field extends a standard entity rather than a custom Table. */ entity_definition_id: Uuid | null; /** The token of the Table this Field belongs to. */ table_token: string | null; key: string; label: string; name: string | null; /** * When this Field was taken away (retired / archived), or null while it is live. Filled by the reads that * can answer a retired Field — `entityFields({ include_retired: true })`; absent from reads that never do. */ archived_at?: string | null; /** FLD-1. Exactly one of five. */ type: FieldBehavior; /** FLD-2. The shape of the value, never a second behavior. */ multi: boolean; /** FLD-2. The values carry their own dates — the world clock, not History. */ dated: boolean; /** FLD-3. Any number of attached validation Rules. */ rules: FieldRule[]; config: Record; required: boolean; default: unknown; sort: number | null; /** The Table this relation points at. */ relation_target: Uuid | null; relation_max: number | null; on_target_delete: OnDelete | null; /** REL-9. The reverse is visible from both ends and is NOT a second Field. */ inverse_key: string | null; /** REL-DISP. Which of the target's columns this one shows. Null = the Table's own. */ display: RelationDisplay | null; source: FieldSource; source_config: Record; /** FLD-9. A Formula declares whether it computes on read or on write. */ compute_on: ComputeOn | null; /** The unit, on the Field, because it changes the meaning. Never presentation. */ unit: string | null; format: string | null; /** AGT-7. A ceiling a merge field's delivery can never widen. */ sensitivity: FieldSensitivity | null; /** FLD-12. Whether an agent may see this Field's values: include · summarize · exclude · on_request. */ context_policy: ContextPolicy | null; /** AGT-6. How often a `source = agent` Field is refilled. */ review_interval_days: number | null; /** * §D says this is on the wrong object and moves to the merge field. It is * still carried here because the live column is, and the client reads what * the store holds — never what the plan wishes it held. */ depends_on: Uuid[] | null; /** FLD-10. Which record types this Field applies to. Empty means all of them. */ applies_to_types: string[]; /** FLD-5 / FLD-6. A list field's choices are the records of THIS Table. */ options_table_id: Uuid | null; created_by: Uuid | null; updated_by: Uuid | null; created_at: Timestamp; updated_at: Timestamp; version: number; metadata: Record; visibility: string; } /** * REC-1. A Table declares its fields, exactly one Home, and the properties * `display`, `ordered`, `heavy` | `light`, `retention` and `detail`. */ interface Table { id: Uuid; organization_id: Uuid; /** * The access ladder's Table "Level": organization · public · confidential · private. Absent is * the organization's own. Confidential and Private records have no "Shown to". */ level?: string | null; /** The token this Table is addressed by. */ slug: string; name: string; label_singular: string | null; label_plural: string | null; icon: string | null; color: string | null; /** REC-32. One of the seven, closed. */ type: TableType; /** REC-11. A detail Table inherits only: no direct shares, never a Home. */ detail: boolean; parent_token: string | null; /** AGT-1 / AGT-2. On by default for a custom table; an organization turns it off. */ agent_writable: boolean; display: TableDisplay | null; ordered: boolean; /** REC-4. `heavy` is indexed with Rules on write; `light` is the whole document with Rules on read. */ weight: StorageMode; /** REC-23. How long a soft delete stays reversible. */ retention_days: number | null; /** REC-2. Every Table has one; without it a record cannot be a chip. */ title_field: string | null; /** * T8 / CD-CORE-15. The Field KEY whose value is each record's type (a Shape's Kind); which columns a record * has follows it (`applies_to_types` on a Field). Absent or null: every record has every column. */ type_field?: string | null; /** The field ids this Table declares, in declaration order. */ fields: Uuid[]; default_sort: string | null; row_order: string | null; /** REC-14. Where this Table lives. Exactly one primary Home. */ home_id: Uuid | null; /** The feature that keeps this Table out of the person's lists (`snapshot`, `copying`, …); absent for a person's own table. */ kept_for?: string | null; /** REC-27. One of the nine, defined in code and not editable by Migration. */ is_kernel: boolean; created_by: Uuid | null; updated_by: Uuid | null; created_at: Timestamp; updated_at: Timestamp; version: number; metadata: Record; /** The old lane word; read `shown_to` and `published_to_web` (access ladder), which the store answers now. */ visibility: string; /** Access ladder "Shown to" (which lists show it; never a lock). Absent on a store that does not answer it. */ shown_to?: string | null; /** Access ladder "Published to the web". Absent on a store that does not answer it. */ published_to_web?: boolean; /** * Lane 10 FD. Part of the business's day-one data (Patients, Therapists, Services) — a mark, not * storage. Absent is false. Only admin on the Table changes it (custom._table_shape_guard). */ foundation?: boolean; /** * Present only on what `tableFind({ …, keptFor })` answers for an ARCHIVED table of that slug and * kept_for (the store's `archived_at`); such an answer carries only `id`, `organization_id` and this. */ archived_at?: Timestamp | null; } /** * Does this column hold NUMBERS the store keeps — a number, money or percent column, or the record number * (`config.system: autonumber`, worked out once on save and kept)? */ declare function holdsNumbers(field: Field): boolean; /** How the store should compare a column's values when it sorts by it. The record number sorts 1, 2 … 10. */ declare function sortAsFor(field: Field): NonNullable; /** One column sort, by Field key — the grid's header sort and the table's default sort share it. */ interface ColumnSort { /** The Field KEY. */ id: string; direction: "asc" | "desc"; } /** A header sort in the store's page-order shape. A sort on a column that is gone is no sort. */ declare function pageSortFor(fields: readonly Field[], sort: ColumnSort | null | undefined): RecordPageSort[]; /** A sort as a view saves it: a Field key and a direction. */ interface SavedSort { field: string; direction: "asc" | "desc"; } /** * THE SORTS AFTER THE FIRST (Airtable's second and third sort keys). A view saves several sorts; the header sets * one. These are the view's remaining ones, kept in order, minus a column the table no longer has, a column already * used, and a column the store cannot sort by (`unsortable`). At most `MAX_SORTS - 1`. */ declare const MAX_SORTS = 3; declare function thenSortsOf(viewSorts: readonly SavedSort[] | null | undefined, fields: readonly Field[], firstKey: string | null | undefined, unsortable?: (field: Field) => boolean): SavedSort[]; /** The store's page order for a first sort followed by the sorts after it. */ declare function pageSortsFor(fields: readonly Field[], first: ColumnSort | null | undefined, then: readonly SavedSort[]): RecordPageSort[]; /** * THE TABLE'S OWN SORT — or `null`. The store writes `default_sort` as `[{field, direction}]` with `field` a Field * KEY; older rows hold a bare key or `"key desc"`, so all three shapes are read. A sort naming a column the table * no longer has is DROPPED, never guessed at. Only the first sort key is used. */ declare function defaultSortOf(table: Pick | null | undefined, fields: readonly Field[]): ColumnSort | null; /** The parts of a grid grouping the reads depend on (records-ui's `GridGrouping` is one). */ interface GroupingShape { field: string; then?: readonly unknown[] | undefined; across?: unknown; trail?: readonly unknown[] | undefined; } /** * A grouping the merged grid keeps as ROWS under group headers: one level, no pivot, no drill trail. Anything else * opens the drill, which reads other doors. */ declare function isPlainGrouping(grouping: G | undefined): grouping is G; /** The page is asked in group order first, then in the sort the person chose. */ declare function groupedPageSort(fields: readonly Field[], groupKey: string | null, sort: RecordPageSort[]): RecordPageSort[]; /** Every summary the store answers (`custom.record_aggregate`); a chosen summary outside it is never sent. */ declare const SUMMARY_OPERATIONS: readonly AggregateOperation[]; /** Every group's count and each chosen summary: `record_aggregate`'s measures when grouped by the grouping column. */ declare function groupFactMeasures(chosen: Record): AggregateMeasure[]; /** The summary bar's measures over the whole table: none when nothing is chosen. */ declare function summaryBarMeasures(chosen: Record): AggregateMeasure[]; /** The keys of the choice columns, in the table's field order: each has a header filter list with counts. */ declare function choiceFieldKeys(fields: readonly Field[]): string[]; /** How many links a grid cell draws of a reverse column (the chips; the rest is "+N"). */ declare const REVERSE_CELL_CHIPS = 3; /** * THE VIEW'S OWN QUESTION, as the grid asks it: its Rule, else its flat filter (an empty flat filter is none). * The grid's column filters are laid over this by records-ui's `storeQuestion`; with none, this is the question. */ declare function viewFilterOf(shown: { where?: StoreFilter | null | undefined; filters?: StoreFilter | null | undefined; } | null, _fields?: readonly Field[]): StoreFilter | undefined; /** Who a question is asked for (the access lanes, applied to counting). */ type DrillLane = "mine" | "organization" | "platform"; type DrillGrain = "hour" | "day" | "week" | "month" | "quarter" | "year"; type DrillMeasureOp = "count" | "count_distinct" | "sum" | "avg" | "min" | "max" | "median" | "percentile" | "rate" | "filled" | "empty" | "ratio" | "sum_of" | "span"; /** * The operations a question may ask ad hoc (`{op, of}`); a ratio, a percentile and a run rate are * declared, never ad hoc (each needs more than a column: its parts, its p, its per). */ type DrillAdHocOp = Exclude; /** * A threshold on the groups of an answer (`having`). Judged on the current window, and applied * BEFORE the cut into Other: a group that misses any threshold is added into Other with the groups * past the limit, so the answer still adds up to its total; `distinct_groups` counts the groups that * met every threshold and the total row says how many did ("3 of 41 groups meet the rule …"). * Exactly one of `value` / `share_of_total` / `times_median`. */ interface DrillHaving { /** A Measure the question shows (a screen shows the number it filters on). */ measure: string; /** At least / more than; at most / less than (lane DRILL-FLIP-FIXES: "groups where cost ≤ 5"). */ op: ">=" | ">" | "<=" | "<"; /** The group's value against a number. */ value?: number; /** The group's value against this percent (0–100] of the window's total; additive Measures only. */ share_of_total?: number; /** The group's value against this multiple of the median group's value. */ times_median?: number; /** With `times_median`: the median of the groups above zero only. */ median_nonzero?: boolean; /** * The address of the drill setting that holds the line (organizations and people decide): * `drill.finding...` inside a finding. When present the setting's value * is the threshold and the number written beside it is its default. Resolved by the door through * platform.drill_knob; clients read the same value from platform.knob_snapshot. */ knob?: string; } /** A question — what a Saved view stores and the explorer's URL encodes. */ interface DrillQuestion { /** Dimension keys, outermost first; a time as `key:grain` ("created_at:week"). At most four. */ by?: string[]; /** One Dimension drawn as the columns of a pivot. */ across?: string; /** Measure keys, or an ad hoc `{op, of}` over a column the definition reads. */ show?: Array; /** * The store's own filter shape: a scalar is an equality, `null` is "not set", a list is any of * them, `{from, to}` is a half-open range; `key:grain` = one period by its label. */ where?: Record; /** * A custom Table only: the view's Rule expression, which must hold beside `where` * (custom.record_drill ANDs the two). A standard source refuses it. */ rule?: RuleExpression; window?: { key?: string; preset?: string; from?: string; to?: string; }; compare?: "previous_period" | "same_period_last_year" | { against: "previous_period" | "same_period_last_year" | "range"; period?: DrillGrain; from?: string; to?: string; baseline?: { from: string; to: string; }; to_date?: boolean; }; sort?: { key: string; direction?: "asc" | "desc"; }; /** Groups per level before Other; the knob's value when absent, never above the page ceiling. */ limit?: number; lane?: DrillLane; /** The drill path a screen's default click follows. */ path?: string; /** Thresholds on the groups, applied before the cut into Other (see DrillHaving). */ having?: DrillHaving[]; /** Records only: the page's start. */ offset?: number; /** Records only: which columns a record shows (a definer definition's records: of its declared columns). */ columns?: string[]; } /** * One client's memory of its own operations. `mint()` names a write and remembers it; `isOwn(opId)` * answers whether a notice is that write's echo. * * OWN-WRITE DETECTION IS PER CLIENT INSTANCE. Two setups in ONE process (a server holding two * identities, a worker beside a UI) must hear each other: a realm-wide ledger made A's write "ours" to * B as well, and B dropped it as an echo (2026-10-08, the README proof). `createRecords` gives every * setup its own ledger and hands it to its client, its entity port and its live-changes port. */ interface OpLedger { mint(): Uuid; isOwn(opId: string | null | undefined): boolean; /** Test seam: forget everything. */ clear(): void; /** Test seam: how many operations are currently remembered. */ readonly size: number; } /** * The data seam: a structural subset of `SupabaseClient`. The package never * opens a database connection of its own and never holds a key — the HOST * supplies a client that already carries the operating person's session, which * is what makes DOOR-5 and AGT-N-4 true (the store sees the person, not us). */ interface RecordsDataSource { /** * Call a door. The name is always a door the live catalog has; `/core` * refuses `door_absent` before it ever reaches here for one that does not. */ rpc(fn: string, args: Record, /** * THE SCHEMA THE DOOR LIVES IN, always supplied: `custom` for the store's * own doors, `iam` for the trust doors (the external principal and the * publish binding, which are the PLATFORM's). A host binding supabase-js * routes this to `client.schema(options.schema).rpc(fn, args)`; a host that * ignores it calls its own default PostgREST profile — `public` — and is * refused by name, which is the failure we want rather than a silent answer * from the wrong system. (Before 2026-09-18 this was described as "only ever * `iam`" and the store's doors went unqualified; the extension's first real * turn proved that asks `public.store_is_open` and finds nothing.) */ options?: { schema?: string; }): PromiseLike<{ data: unknown; error: PgError | null; }>; /** * OPTIONAL. True for the real supabase adapters: the client may open a table page with ONE * `custom.table_page_bundle` call instead of a dozen shape doors one after another (PAGE-BUNDLE). * Leave it off for a test or replay source that does not model the bundle door. */ opensInOneCall?: boolean; /** Reads of `custom.*` go through the schema-qualified builder, never a bare `from`. */ schema(name: string): { from(table: string): RecordsTableQuery; }; } /** The read surface the list and query paths use. A real supabase-js client satisfies it. */ interface RecordsTableQuery { select(columns: string, options?: { count?: "exact" | "planned" | "estimated"; head?: boolean; }): RecordsFilter; } interface RecordsFilter extends PromiseLike { eq(column: string, value: unknown): RecordsFilter; neq(column: string, value: unknown): RecordsFilter; in(column: string, values: readonly unknown[]): RecordsFilter; is(column: string, value: null | boolean): RecordsFilter; gte(column: string, value: unknown): RecordsFilter; lte(column: string, value: unknown): RecordsFilter; order(column: string, options?: { ascending?: boolean; }): RecordsFilter; range(from: number, to: number): RecordsFilter; limit(count: number): RecordsFilter; } interface RecordsResponse { data: unknown; error: PgError | null; count?: number | null; } /** * WHO IS ACTING. AGT-N-4: an agent carries the exact authority of the person * operating it — there is no agent identity and there are no service roles. So * the actor word and the person are two separate facts, and `on_behalf_of` is * meaningful only when the actor is `agent`. */ interface RecordsActor { actor: Actor; /** The signed-in person. The store reads this from the session, not from us; this is for the client's own mirror. */ user_id?: Uuid; /** Only an agent acts on behalf of a person (the store refuses it otherwise). */ on_behalf_of?: Uuid; } /** * OPTIONAL. A live-updates seam. The default degradation is stated rather than * silent: with no port bound, `useRecords` reports `live: false` and the screen * can say "not live" instead of quietly going stale. * * A host binds this with `@ai-matrx/data/react`'s channel hygiene — the package * deliberately does NOT depend on it, so the headless core stays free of a * realtime client and a host that has one keeps using the one it already has. */ interface RecordsRealtimePort { /** * Watch one organization's records of one table. Returns an unsubscribe. * * THE HOST NUDGES THROUGH THIS SINK AND REACHES AROUND NOTHING. Until 0.43.0 the callback * was `(recordId: Uuid) => void` and a host that also wanted to say "the SHAPE moved" * imported `tableShapeChanged` from `@ai-matrx/records/react` and called it directly — * which worked, and which meant the port contract did not describe half of what a port * actually does. A column appearing is not a row changing, and the package owns the * difference. * * NOTHING THAT ARRIVES HERE IS DATA. A nudge has not passed the read door, so the hook * re-reads — by id set when the nudge names ids, whole-page when it cannot. */ subscribeRecords(args: { organization_id: Uuid; table_id: Uuid; }, sink: RecordsChangeSink): () => void; } /** What a realtime port may tell the package. Two calls, because a column is not a row. */ interface RecordsChangeSink { /** * THESE RECORDS MOVED. `null` means "I cannot tell you which" — a reconnect, a tab wake, or * a change above the store's own id cap — and is the one case that costs a whole-page read. * An EMPTY array is not the same thing and is not a nudge at all. */ records(ids: readonly Uuid[] | null): void; /** * THIS TABLE'S SHAPE MOVED — a column added, retired or changed. Re-reading the rows would * redraw the same table without the new column in it, which is a screen that is out of date * while looking healthy. */ shape(): void; } /** * OPTIONAL. Where a refusal that nobody asked about goes — the loud funnel. * Default degradation: `console.error` with the store's own words, never * silence. */ type RecordsErrorSink = (error: { code: string; message: string; hint?: string; where: string; }) => void; /** * OPTIONAL. The merge-field resolver's server half (`W5-MERGE-B`). While it is * not bound, `useMergeField` answers `pending` WITH THE REASON — never a blank, * never a literal placeholder left in the text (DYN-14). */ interface RecordsResolverPort { resolve(args: { organization_id: Uuid; merge_field_keys: string[]; /** The live selection the `state` source reads (DYNAMIC-VALUES §C). */ state?: Record; }): Promise; } /** The one config a host binds. */ interface RecordsConfig { /** REQUIRED. */ dataSource: RecordsDataSource; /** REQUIRED. */ actor: RecordsActor; /** * REQUIRED. REC-29: organizations are hard walls, and the store is keyed * `(organization_id, id)`. There is no "current organization" this package * discovers for itself — the host says which one, every time. * * `null` is the ALL-ORGANIZATIONS mode (access belongs to the person, not the selected * organization): a host whose page lists across every organization the person belongs to * mounts with none. Doors that answer for the person (`custom.data_home*`) take it; a door that * needs one is sent NULL and refuses in its own words, never a guessed organization. */ organizationId: Uuid | null; /** * EVERY organization the person belongs to (active-org-is-never-a-list-filter.md). * `organizationId` above is where NEW things are written and which org a write * runs in; it never decides what a READ shows. With this set, `tableList` / * `tableFacts` span all of these organizations (or one, when the page passes * its `organization_id` filter), and `tableRead` / `recordRead` / * `recordValuesVersioned` open a record in ITS OWN organization. Absent ⇒ the * client reads only `organizationId`, exactly as before. */ organizationIds?: readonly Uuid[]; realtime?: RecordsRealtimePort; /** * This client's own-write memory (`createOpLedger()`). Hand the SAME ledger to the live-changes port * that listens for this client. Absent ⇒ the realm's default ledger (one client per browser tab). */ opLedger?: OpLedger; onError?: RecordsErrorSink; resolver?: RecordsResolverPort; /** * The schema the record store lives in. Exists so a rehearsal branch and * production can differ without a fork; it is `custom` everywhere today. */ schema?: string; /** * Doors the generated catalog (`STORE_DOORS`) does not list YET but this store is known to have — * the nightly clone after a rehearsal, a test store. A screen reading an owed door asks * `doorReady(config, name)` first, so production (which lacks the door until the chair applies it) * is never asked and logs nothing. Leave it out in a shipped host: the regenerated catalog is * the switch. */ knownDoors?: readonly string[]; } type WhereOp = "eq" | "neq" | "lt" | "lte" | "gt" | "gte" | "contains" | "in" | "empty"; interface WhereClause { column: string; op: WhereOp; value?: unknown; } type Lane = "all" | "mine" | "team" | "orgs" | "shared" | "public" | "system"; /** §4. A question of one source. Every clause must hold. */ interface Query { where?: WhereClause[]; search?: string; sort?: { column: string; direction?: "asc" | "desc"; }[]; pageSize?: number; /** Default: the type's "Shown to by default" knob. A custom table has one lane: what row security shows. */ lane?: Lane; /** A filter, never a lock. Default "all". */ org?: Uuid | "all"; /** * THE ARCHIVE (the archived-items law): `true` answers the rows that were archived instead of the live * ones, newest-archived first, each carrying `_archived_at` and `_archived_by_name`, so a screen can offer * Restore. The archive door takes no `where` / `search` / `sort`: they are not applied to it. */ archived?: boolean; } /** A view's look as the store keeps it: one JSON object under `definition.presentation`. */ type ViewPresentationDocument = Record; /** * HOW A VIEW'S LOOK IS READ AND WRITTEN — a PORT. The store keeps the look as one JSON object; what it * means (colors, formats, frozen columns) belongs to the screens that draw it, so the screens hand their * codec in (`@ai-matrx/records-ui` binds its grid presentation). Left out, the look stays the plain * document the store keeps — a headless host reads and writes it untouched. */ interface ViewPresentationCodec

{ parse(raw: unknown): P; isEmpty(presentation: P): boolean; /** The look as the JSON object the store keeps. */ toDocument(presentation: P): Record; } /** The ways one saved view can be looked at (SCR-6; the timeline, lane VIEWS-AND-FIELDS TL). */ declare const VIEW_LAYOUTS: readonly ["grid", "kanban", "calendar", "gallery", "timeline", "list", "chart", "map", "orgchart", "pivot", "swipe"]; type ViewLayout = (typeof VIEW_LAYOUTS)[number]; /** One sort clause. The Field's key and a direction; nothing else is a sort. */ interface ViewSort { field: string; direction: "asc" | "desc"; } /** How a saved view is ordered: by hand, by its sort, or it never said (the same as sorted). */ type ViewOrder = "manual" | "sorted" | null; /** * THE DECLARATIVE SPEC. An agent writes this whole object; a person tweaks it. * Every builder component in this package takes one of these as a prop. */ interface SavedViewSpec

{ name: string; /** The Table this view looks at. */ subject: Uuid; layout: ViewLayout; /** Kanban: the Field whose value becomes a column. */ groupField?: string | null; /** * Kanban: a number Field to TOTAL under each column heading. It lives on the VIEW for * the same reason the colors do — two people read one board two ways and neither * reading is a fact about the records. */ measure?: string | null; /** Chart: how it draws: bar, line, donut, area, pie, stacked or scatter (`chart_kind`). */ chartKind?: string | null; /** Chart: what it measures per group, `count`, `sum` or `avg` (`chart_measure`). */ chartMeasure?: string | null; /** Pivot: the Field whose values are the columns; chart: a stacked bar's series (`column_field`). */ columnField?: string | null; /** Pivot: what each cell measures: count, sum, avg, min or max (`pivot_measure`). */ pivotMeasure?: string | null; /** Scatter chart: the number Field along the bottom (`x_field`). */ xField?: string | null; /** * Kanban: the Field whose values cut the board into SWIMLANES across the columns — a * dispatcher's board by Status, one lane per Technician (S1-PRIME VIEW-KEYS). Never the * column Field itself; the store refuses that. */ swimlaneField?: string | null; /** Kanban: the columns this view keeps shut to a strip, by the column's stored value. */ collapsedColumns?: string[]; /** Calendar: the Field that places a record in the month. */ dateField?: string | null; /** Timeline: the Field a record's bar starts on (`start_field`). */ startField?: string | null; /** Calendar and timeline: the Field a record ends on (`end_field`). */ endField?: string | null; /** Gallery: the Field shown large on the card. */ imageField?: string | null; /** Map: the address, place or latitude Field that puts a record on the map (`map_field`). */ mapField?: string | null; /** Map: the longitude Field when `mapField` is a latitude Field (`map_lng_field`). */ mapLngField?: string | null; /** Org chart: the link Field (to this same table) that says who a record reports to (`parent_field`). */ parentField?: string | null; /** Swipe: the Field each answer is written to; a choice column's options are the answers (`answer_field`). */ answerField?: string | null; /** Swipe: the Field holding when a card is asked — a condition over earlier cards (`condition_field`). */ conditionField?: string | null; sorts?: ViewSort[]; /** * HOW THE VIEW IS ORDERED (ORDER-FIX): `"manual"` — the positions a person set by hand ARE the * view's sort, and it carries no `sorts`; `"sorted"` or null — by `sorts`. READ ONLY: the store * writes "manual" only when the rows are placed (`custom.view_record_order_set`) and turns it * off itself when a sort is saved, so no patch ever sends it (`viewSettingsPatch` does not). */ order?: ViewOrder; /** * The membership Rule. The STORE decides who is in this view; this is a * reference to its Rule record, never a predicate this package evaluates. */ ruleId?: Uuid | null; /** * THE FLAT FILTER a digest or a notify rule wrote the view with — the one shape * `custom.record_filter_sql` compiles, by Field KEY. A view saved in the bar has * none; a view saved by `DigestScheduler` ("where Status is Open") does, and the * grid and the board show exactly the records it names. */ filters?: RecordFilter; /** * S2-PRIME — THE VIEW'S OWN QUESTION, as the condition builder writes it: the store's Rule * shape `{op, args}`, ALL / ANY / NOT groups nested to any depth, Fields by id. Kept in the * definition as `where` and asked of the store unchanged — the grid's list door, the board's * headings and the dashboard's numbers compile it into the one WHERE clause * (`custom.record_filter_sql`). Never stored under `filters`: that key is the flat map the * digests and the notifier read, and they would refuse it by name. */ where?: RuleExpression | null; isDefault?: boolean; /** PERSONAL (Airtable): only the person who made the view lists it. Absent/false = collaborative. */ personal?: boolean; /** The named section of the view list this view sits under (VIEWS-AIRTABLE). Null/absent = unsectioned. */ section?: string | null; /** Where the view sits in the view list among its section's views, lowest first (VIEWS-AIRTABLE). */ position?: number | null; /** * HOW THIS VIEW LOOKS — its colors, its per-column formats and its frozen * column (`presentation.ts`). * * It lives on the VIEW and not on the Fields because two people read one * table two ways and neither reading is a fact about the records; it lives on * a RECORD, not a new column, because that is what makes it something an * agent writes with the same `records` tool as everything else. */ presentation?: P; } /** * A saved view as it comes back out of the store, with its row's own id. * * It carries no version: `custom.view_declare` MERGES one key at a time, so two * tabs pressing two different controls on one view both stand, and one control * pressed in both keeps the latest — how Airtable and Notion keep a view change. */ interface SavedView

extends SavedViewSpec

{ id: Uuid; /** Where the view came from when it was moved in (the mover, the S0 repair), else null. */ movedFrom: Record | null; } /** The table page's own page size (100 unless embedded). */ declare const TABLE_PAGE_SIZE = 100; /** How many rows an embedded table reads at a time: its first page, and each "Show more". */ declare const EMBEDDED_PAGE_SIZE = 50; interface FirstGridPageArgs { p_table_id: Uuid; p_filter: StoreFilter | Record; p_search: null; p_sort: RecordPageSort[]; p_view_id: null; p_limit: number; p_offset: 0; } /** The request for the plain opening, from what the screen itself reads — or null. Pure. */ declare function firstGridPageArgs

(input: { tableId: Uuid; table: Pick | null; fields: readonly Field[]; /** The view as THIS person sees it (the saved view with her look over it), or null for none. */ shown: SavedView

| null; pageSize?: number; /** * The host draws the MERGED grid, which keeps a plain grouping as rows under group headers: the page is then * read in group order. The classic grid opens the drill for a grouped view, so a grouped view stays unseeded. */ merged?: boolean; }): FirstGridPageArgs | null; type OpeningOptions

= { pageSize?: number; merged?: boolean; view?: SavedViewSpec

| undefined; codec?: ViewPresentationCodec

; }; /** * Read what the screen reads (through `client`, e.g. one served from `custom.table_page_bundle`) and build the first * page's request. Null when anything it needs is not answered. */ declare function firstGridPageRequest

(client: Pick, tableId: Uuid, options?: Omit, "view">): Promise; /** * THE PERSON'S SERVER-ROWS KNOBS, FROM THE TABLE'S BUNDLE: `custom.table_page_bundle` carries a `server_rows` part * (whether the page may wait for the server's rows, and for how long) resolved for the person asking. Null when the * seed holds no such answer (an older store, a refused part): the host treats that as off. */ declare function serverRowsOf(seed: RecordsSeed | null | undefined): { on: boolean; capMs: number | null; } | null; /** * A TABLE PAGE'S SEED, ASKED BY THE SERVER AS THE PERSON. * * Asks what the table page opens on — the table's bundle, the grid's first page when it can be predicted, and on a * record page the record's bundle — through a recording data source, and answers every door answer it got as a * `RecordsSeed`. The host hands that to `` (`@ai-matrx/records/react`) above the table page. * `dataSource` is the person's own (a server Supabase client carrying her session). Never throws. */ declare function askTablePageSeed

(input: { dataSource: unknown; organizationId: Uuid; tableId: Uuid; actor: RecordsConfig["actor"]; /** A record page: its record's bundle (`custom.record_page_bundle`) is asked beside the table's. */ recordId?: Uuid | null; /** * Ask the grid's first page (default true). A function decides once the table's bundle has been answered — it is * handed everything asked so far, so a host can read the person's `server_rows` knob (`serverRowsOf`) first. */ rows?: boolean | ((asked: RecordsSeed) => boolean); /** The table is drawn EMBEDDED: its page size. */ embedded?: boolean; pageSize?: number; /** The host draws the merged grid: a view grouped by one field is seeded too (group counts, summary bar, link words). */ merged?: boolean; /** THE VIEW THE HOST HANDS THE GRID, for a table with no saved view behind it. */ view?: SavedViewSpec

| undefined; /** The host's view codec (records-ui binds its grid look). Left out: the plain document. */ codec?: ViewPresentationCodec

; }): Promise; type Base = { dataSource: unknown; organizationId: Uuid; actor: RecordsConfig["actor"]; }; /** A standard source's first read: its page size and the viewer's search (an empty search is none). */ declare function entityTableQuery(options?: { pageSize?: number | undefined; search?: string | null | undefined; }): Query; /** The block's own props that decide a chart's question. */ interface EntityChartQuestionInput { /** The Dimension to group by. Absent: one total. */ by?: string | undefined; /** What to count: the rows (default) or a number column summed. */ measure?: { op: "count"; } | { op: "sum" | "avg" | "min" | "max"; of: string; } | undefined; where?: Record | undefined; organization?: string | undefined; } /** The chart's `platform.drill_ask` question. */ declare function entityChartQuestion(input: EntityChartQuestionInput): DrillQuestion & { organization?: string; }; /** Several seeds as one: the later answer wins on the same door and arguments; `at` is the oldest. */ declare function mergeSeeds(...seeds: Array): RecordsSeed; /** * AN ENTITY SOURCE'S BLOCK (a table, board or card of "task", "project", "crm_deal"): its columns and first page, * asked through the entity engine's own port with the question the block's `useEntityTable` sends. Never throws. */ declare function askEntityBlockSeed(input: Base & { token: string; question?: { pageSize?: number | undefined; search?: string | null | undefined; }; }): Promise; /** AN ENTITY SOURCE'S CHART: `platform.drill_ask` with the question the block sends. */ declare function askChartSeed(input: Base & { source: { kind: "entity"; token: string; }; question?: EntityChartQuestionInput; }): Promise; /** One aggregate question of a tile: `client.recordAggregate`'s arguments but the table. */ type TileSpec = Omit[0], "table_id">; /** A TABLE'S TILE: `custom.record_aggregate` over `tableId` for each `spec`. Read back with `useSeededAggregate`. */ declare function askTileSeed(input: Base & { tableId: Uuid; spec: TileSpec | TileSpec[]; }): Promise; /** * THE FIRST PAGE WITH A HOST'S VIEW CODEC BOUND ONCE (records-ui binds its grid look): the host re-exports these * under the same names — bindings of the one definition here, never a second body. */ declare function bindFirstPageCodec

(codec: ViewPresentationCodec

): { firstGridPageRequest: (client: Pick, tableId: Uuid, options?: { pageSize?: number; merged?: boolean; }) => Promise; askTablePageSeed: (input: Omit>[0], "codec">) => Promise; }; export { EMBEDDED_PAGE_SIZE, MAX_SORTS, REVERSE_CELL_CHIPS, SUMMARY_OPERATIONS, TABLE_PAGE_SIZE, askChartSeed, askEntityBlockSeed, askTablePageSeed, askTileSeed, bindFirstPageCodec, choiceFieldKeys, defaultSortOf, entityChartQuestion, entityTableQuery, firstGridPageArgs, firstGridPageRequest, groupFactMeasures, groupedPageSort, holdsNumbers, isPlainGrouping, mergeSeeds, pageSortFor, pageSortsFor, serverRowsOf, sortAsFor, summaryBarMeasures, thenSortsOf, viewFilterOf }; export type { ColumnSort, EntityChartQuestionInput, FirstGridPageArgs, GroupingShape, SavedSort, TileSpec };