{"version":3,"sources":["../../src/views/index.ts","../../src/views/keys.ts","../../src/views/views.ts","../../src/views/look.ts","../../src/views/bind.ts","../../src/aggregate.ts","../../src/relativeDays.ts"],"sourcesContent":["// @ai-matrx/records/views — SAVED VIEWS, HEADLESS: the declared keys of a view (`VIEW_KEYS`), the one reader\n// (`viewSettings`) and writer (`viewSettingsPatch`), the declarative spec (`SavedViewSpec`), and the doors that\n// keep it (`declareView`, `saveViewPatch`, `designateView`). Zero React, zero design-system: a view's look is a\n// codec port (`ViewPresentationCodec`); `@ai-matrx/records-ui` binds its grid look, a headless host keeps the\n// plain document. (Moved from records-ui views.ts / viewKeys.ts, step 10, 2026-10-08.)\n\nexport * from \"./keys\";\nexport * from \"./views\";\nexport * from \"./look\";\nexport * from \"./bind\";\n\n// The store's \"is this filter a Rule\" test, for a reader that must not load the root (records-ui's\n// light `/helpers` entry reads it through `isPage`; records-ui front door, 2026-10-17).\nexport { isRuleFilter } from \"../aggregate\";\n\n// The reader's zone a relative day (\"Today\", \"Overdue\") is cut in, for a host that mirrors the person's zone\n// without loading the root (records-ui's light `/helpers` entry sets it through `setPersonTimeZone`).\nexport { setReadersTimeZone, readersTimeZone } from \"../relativeDays\";\n","// src/views/keys.ts — @ai-matrx/records/views (headless; moved from records-ui viewKeys.ts, step 10 2026-10-08)\n// · lane S1-PRIME VIEW-KEYS (UI-CHAMPIONS-PLAN rev 2)\n//\n// EVERY PER-VIEW SETTING IS A DECLARED KEY OF THE ONE SAVED VIEW.\n//\n// A saved view is one row of `platform.saved_view` (lane S0). What it may hold is decided in ONE\n// place: `custom.view_keys()`, the registry `custom.view_declare` judges every save against. This\n// file is that registry's client half and the ONE accessor every layout reads a view through:\n//\n//   - `VIEW_KEYS` mirrors `custom.view_keys()` row for row (path, shape, the layouts that read it,\n//     who may write it). The live walk compares the two through REST, as test@test.com, so a key\n//     added on one side and not the other fails a walk, never a person.\n//   - `viewSettings(definition)` is THE reader: a stored definition in, every declared key out,\n//     typed. `viewFromRow` (views.ts) goes through it, so the Grid, the board, the calendar,\n//     and the gallery all see a view the same way.\n//   - `viewSettingsFor(view, layout)` hands a layout only the keys it reads; a layout that does\n//     not use a key never sees it (the calendar is never told about swimlanes).\n//   - `viewSettingsPatch(patch)` is THE writer's shape: only the keys a press changed, a cleared\n//     key as null (the door removes it). `saveViewPatch` sends it through `custom.view_declare`.\n//\n// Fields are named by KEY (a Field's key is immutable; every reader draws rows by key). The door\n// accepts an id and stores the key, so an agent may send either.\n\nimport type { RecordFilter, RuleExpression } from \"@ai-matrx/records\";\n\n/** A view's look as the store keeps it: one JSON object under `definition.presentation`. */\nexport type ViewPresentationDocument = Record<string, unknown>;\n\n/**\n * HOW A VIEW'S LOOK IS READ AND WRITTEN — a PORT. The store keeps the look as one JSON object; what it\n * means (colors, formats, frozen columns) belongs to the screens that draw it, so the screens hand their\n * codec in (`@ai-matrx/records-ui` binds its grid presentation). Left out, the look stays the plain\n * document the store keeps — a headless host reads and writes it untouched.\n */\nexport interface ViewPresentationCodec<P> {\n  parse(raw: unknown): P;\n  isEmpty(presentation: P): boolean;\n  /** The look as the JSON object the store keeps. */\n  toDocument(presentation: P): Record<string, unknown>;\n}\n\n/** The look as the plain JSON document the store keeps (no screen's meaning applied). */\nexport const plainPresentation: ViewPresentationCodec<ViewPresentationDocument> = {\n  parse: (raw) => (raw && typeof raw === \"object\" && !Array.isArray(raw) ? { ...(raw as Record<string, unknown>) } : {}),\n  isEmpty: (presentation) => Object.keys(presentation).length === 0,\n  toDocument: (presentation) => ({ ...presentation }),\n};\n\nfunction plainCodec<P>(): ViewPresentationCodec<P> {\n  return plainPresentation as unknown as ViewPresentationCodec<P>;\n}\n\n/** Every surface a saved view is drawn by. */\nexport type ViewKeyLayout = \"grid\" | \"kanban\" | \"calendar\" | \"gallery\" | \"timeline\" | \"list\" | \"chart\" | \"map\" | \"orgchart\" | \"pivot\" | \"swipe\";\n\n/**\n * 🚩 THE ONE SWITCH FOR THE TIMELINE'S STORE KEYS (lane VIEWS-AND-FIELDS, sublane TL).\n *\n * `vk_a_calendar_keeps_where_a_record_ends_and_a_timeline_is_a_view.sql` (sublane VK) teaches\n * `custom.view_keys()` the layout `timeline`, the keys `start_field` and `end_field` (calendar +\n * timeline), and `group_field` for the timeline. Until that migration is on production this stays\n * `false`, and:\n *   · `timeline` is not a layout the store keeps (`STORE_KEPT_LAYOUTS`), so it is drawn for the visit;\n *   · `start_field` / `end_field` are held for the visit, never sent (`viewSettingsPatch`), and the\n *     Start also rides `date_field`, which the store already keeps;\n *   · the timeline's toolbar says \"Kept for this visit only\".\n * Flipped to `true`, VIEW_KEYS below mirrors the migrated registry row for row (the live walk\n * compares them) and every one of those is kept on the view.\n */\nexport const STORE_KEEPS_TIMELINE = true;\n\n/**\n * 🚩 THE ONE SWITCH FOR THE SWIPE DECK'S STORE KEYS (2026-10-22). The swipe layout (a table asked one\n * record at a time, `answer_field` written by each answer, `condition_field` deciding when a card is\n * asked). `custom.view_keys()` and `custom._view_key_value('kind')` admit it (applied to Matrx Main\n * 2026-10-22), so it is `true`: the layout and its two keys are kept on the view. Turned `false`, the\n * layout is drawn for the visit and its keys are held for the visit, as the timeline once was.\n */\nexport const STORE_KEEPS_SWIPE = true;\n\n/** Who may write a key: anyone who may save the view, an input the door rewrites, or the server only. */\nexport type ViewKeyWriter = \"caller\" | \"input\" | \"server\";\n\nexport interface ViewKeyDeclaration {\n  /** Where it lives in `platform.saved_view.definition` (dotted under `presentation`). */\n  path: string;\n  /** What the store's guard checks (`custom._view_key_value`). */\n  shape: string;\n  /** The layouts that read it. */\n  layouts: readonly ViewKeyLayout[];\n  writer: ViewKeyWriter;\n}\n\nconst ALL: readonly ViewKeyLayout[] = [\"grid\", \"kanban\", \"calendar\", \"gallery\", ...(STORE_KEEPS_TIMELINE ? ([\"timeline\"] as const) : []), \"list\", \"chart\", \"map\", \"orgchart\", \"pivot\", ...(STORE_KEEPS_SWIPE ? ([\"swipe\"] as const) : [])];\n/** The layouts whose cards draw the fields a view leaves shown (`presentation.hiddenFields`). */\nconst HIDES: readonly ViewKeyLayout[] = [\"grid\", \"gallery\", \"kanban\", \"calendar\", ...(STORE_KEEPS_TIMELINE ? ([\"timeline\"] as const) : []), \"list\"];\nconst GRIDS: readonly ViewKeyLayout[] = [\"grid\"];\nconst BOARD: readonly ViewKeyLayout[] = [\"kanban\"];\n\n/**\n * THE REGISTRY, as `custom.view_keys()` declares it (uichamp_s1_a_view_keeps_every_setting_it_is_given.sql).\n * Order and content are compared with the store by the live walk.\n */\nexport const VIEW_KEYS: readonly ViewKeyDeclaration[] = [\n  { path: \"layout\", shape: \"kind\", layouts: ALL, writer: \"caller\" },\n  { path: \"filters\", shape: \"filter\", layouts: ALL, writer: \"caller\" },\n  { path: \"where\", shape: \"rule\", layouts: ALL, writer: \"caller\" },\n  { path: \"group_field\", shape: \"field\", layouts: [\"kanban\", ...(STORE_KEEPS_TIMELINE ? ([\"timeline\"] as const) : []), \"chart\", \"pivot\"], writer: \"caller\" },\n  { path: \"column_field\", shape: \"field\", layouts: [\"chart\", \"pivot\"], writer: \"caller\" },\n  { path: \"x_field\", shape: \"field:number\", layouts: [\"chart\"], writer: \"caller\" },\n  { path: \"swimlane_field\", shape: \"field:lane\", layouts: [\"kanban\"], writer: \"caller\" },\n  { path: \"collapsed_columns\", shape: \"values\", layouts: [\"kanban\"], writer: \"caller\" },\n  { path: \"measure\", shape: \"field:number\", layouts: [\"kanban\", \"chart\", \"pivot\"], writer: \"caller\" },\n  { path: \"pivot_measure\", shape: \"pivot_measure\", layouts: [\"pivot\"], writer: \"caller\" },\n  { path: \"chart_kind\", shape: \"chart_kind\", layouts: [\"chart\"], writer: \"caller\" },\n  { path: \"chart_measure\", shape: \"chart_measure\", layouts: [\"chart\"], writer: \"caller\" },\n  { path: \"date_field\", shape: \"field:date\", layouts: [\"calendar\"], writer: \"caller\" },\n  ...(STORE_KEEPS_TIMELINE\n    ? ([\n        { path: \"start_field\", shape: \"field:date\", layouts: [\"timeline\"], writer: \"caller\" },\n        { path: \"end_field\", shape: \"field:date\", layouts: [\"calendar\", \"timeline\"], writer: \"caller\" },\n      ] as const)\n    : []),\n  { path: \"map_field\", shape: \"field\", layouts: [\"map\"], writer: \"caller\" },\n  { path: \"map_lng_field\", shape: \"field:number\", layouts: [\"map\"], writer: \"caller\" },\n  { path: \"parent_field\", shape: \"field\", layouts: [\"orgchart\"], writer: \"caller\" },\n  { path: \"image_field\", shape: \"field\", layouts: [\"gallery\"], writer: \"caller\" },\n  ...(STORE_KEEPS_SWIPE\n    ? ([\n        { path: \"answer_field\", shape: \"field\", layouts: [\"swipe\"], writer: \"caller\" },\n        { path: \"condition_field\", shape: \"field\", layouts: [\"swipe\"], writer: \"caller\" },\n      ] as const)\n    : []),\n  { path: \"sorts\", shape: \"sorts\", layouts: ALL, writer: \"caller\" },\n  { path: \"rule_id\", shape: \"uuid\", layouts: ALL, writer: \"caller\" },\n  { path: \"is_default\", shape: \"boolean\", layouts: ALL, writer: \"caller\" },\n  { path: \"presentation\", shape: \"presentation\", layouts: ALL, writer: \"caller\" },\n  { path: \"presentation.style\", shape: \"style\", layouts: ALL, writer: \"caller\" },\n  { path: \"presentation.formats\", shape: \"object\", layouts: GRIDS, writer: \"caller\" },\n  { path: \"presentation.frozen\", shape: \"fields\", layouts: GRIDS, writer: \"caller\" },\n  { path: \"presentation.grouping\", shape: \"grouping\", layouts: [\"grid\", \"gallery\", \"list\"], writer: \"caller\" },\n  { path: \"presentation.widths\", shape: \"widths\", layouts: GRIDS, writer: \"caller\" },\n  { path: \"presentation.rowHeight\", shape: \"row_height\", layouts: GRIDS, writer: \"caller\" },\n  { path: \"presentation.hiddenFields\", shape: \"fields\", layouts: HIDES, writer: \"caller\" },\n  { path: \"presentation.cardHidden\", shape: \"fields\", layouts: [\"kanban\", \"calendar\", ...(STORE_KEEPS_TIMELINE ? ([\"timeline\"] as const) : []), \"list\", \"map\", \"orgchart\", \"gallery\", ...(STORE_KEEPS_SWIPE ? ([\"swipe\"] as const) : [])], writer: \"caller\" },\n  { path: \"presentation.columnOrder\", shape: \"fields\", layouts: GRIDS, writer: \"caller\" },\n  { path: \"presentation.gallerySize\", shape: \"gallery_size\", layouts: [\"gallery\"], writer: \"caller\" },\n  { path: \"presentation.boardSize\", shape: \"gallery_size\", layouts: BOARD, writer: \"caller\" },\n  { path: \"presentation.boardPreview\", shape: \"field\", layouts: BOARD, writer: \"caller\" },\n  { path: \"presentation.boardHideEmpty\", shape: \"boolean\", layouts: BOARD, writer: \"caller\" },\n  { path: \"presentation.boardColorColumns\", shape: \"boolean\", layouts: BOARD, writer: \"caller\" },\n  { path: \"presentation.boardCounts\", shape: \"boolean\", layouts: BOARD, writer: \"caller\" },\n  { path: \"presentation.boardLanesShut\", shape: \"values\", layouts: BOARD, writer: \"caller\" },\n  { path: \"presentation.chartLabels\", shape: \"boolean\", layouts: [\"chart\"], writer: \"caller\" },\n  { path: \"presentation.chartLegend\", shape: \"boolean\", layouts: [\"chart\"], writer: \"caller\" },\n  ...(STORE_KEEPS_TIMELINE ? ([{ path: \"presentation.gantt\", shape: \"object\", layouts: [\"timeline\"], writer: \"caller\" }] as const) : []),\n  { path: \"presentation.locked\", shape: \"boolean\", layouts: ALL, writer: \"caller\" },\n  { path: \"presentation.wrap\", shape: \"boolean\", layouts: GRIDS, writer: \"caller\" },\n  { path: \"presentation.headerWrap\", shape: \"boolean\", layouts: GRIDS, writer: \"caller\" },\n  { path: \"presentation.wrapColumns\", shape: \"fields\", layouts: GRIDS, writer: \"caller\" },\n  { path: \"presentation.fit\", shape: \"fit\", layouts: GRIDS, writer: \"caller\" },\n  { path: \"presentation.freezeFirst\", shape: \"boolean\", layouts: GRIDS, writer: \"caller\" },\n  { path: \"presentation.footer\", shape: \"footer\", layouts: GRIDS, writer: \"caller\" },\n  { path: \"presentation.summaries\", shape: \"summaries\", layouts: GRIDS, writer: \"caller\" },\n  { path: \"grid\", shape: \"grid\", layouts: GRIDS, writer: \"caller\" },\n  { path: \"personal\", shape: \"boolean\", layouts: ALL, writer: \"caller\" },\n  // WITHHELD-HONEST 3: a view the platform made for its own use (a scheduled summary's question); listed to nobody.\n  { path: \"system\", shape: \"boolean\", layouts: ALL, writer: \"caller\" },\n  { path: \"section\", shape: \"section\", layouts: ALL, writer: \"caller\" },\n  { path: \"position\", shape: \"position\", layouts: ALL, writer: \"caller\" },\n  { path: \"hidden_fields\", shape: \"input\", layouts: HIDES, writer: \"input\" },\n  { path: \"table_id\", shape: \"server\", layouts: ALL, writer: \"server\" },\n  { path: \"order\", shape: \"server\", layouts: GRIDS, writer: \"server\" },\n  { path: \"moved_from\", shape: \"server\", layouts: ALL, writer: \"server\" },\n];\n\n/**\n * THE LAYOUTS THE STORE KEEPS ON A VIEW. `custom.view_keys()` judges a view's `layout` against its\n * own list (grid, kanban, calendar, gallery) and refuses any other word by name. A layout this\n * package draws before the store keeps it — the timeline, 2026-10-02 — is never sent as a view's or a\n * look's layout (`viewSettingsPatch`, `viewDocument`): it is drawn for this visit and says so. When the\n * store's registry admits it, add it here and nothing else changes.\n */\nexport const STORE_KEPT_LAYOUTS: readonly string[] = [\"grid\", \"kanban\", \"calendar\", \"gallery\", ...(STORE_KEEPS_TIMELINE ? [\"timeline\"] : []), \"list\", \"chart\", \"map\", \"orgchart\", \"pivot\", ...(STORE_KEEPS_SWIPE ? [\"swipe\"] : [])];\n\n/** Whether the store keeps this layout on a saved view. */\nexport function storeKeepsLayout(layout: string): boolean {\n  return STORE_KEPT_LAYOUTS.includes(layout);\n}\n\n/** The keys one layout reads, by path. */\nexport function viewKeysFor(layout: ViewKeyLayout): string[] {\n  return VIEW_KEYS.filter((k) => k.layouts.includes(layout)).map((k) => k.path);\n}\n\n/** One sort clause: a Field key and a direction. */\nexport interface ViewSortKey {\n  field: string;\n  direction: \"asc\" | \"desc\";\n}\n\n/**\n * EVERY DECLARED KEY OF A VIEW, TYPED. Absent keys are `null` / empty, never guessed.\n * `presentation` is the parsed look (color field, pinned fields, row height, grouping with its\n * sub-groups and shut sections, hidden fields, gallery size, summaries).\n */\nexport interface ViewSettings<P = ViewPresentationDocument> {\n  layout: \"grid\" | \"kanban\" | \"calendar\" | \"gallery\" | \"timeline\" | \"list\" | \"chart\" | \"map\" | \"orgchart\" | \"pivot\" | \"swipe\";\n  filters: RecordFilter | null;\n  where: RuleExpression | null;\n  groupField: string | null;\n  swimlaneField: string | null;\n  collapsedColumns: string[];\n  measure: string | null;\n  /** Chart: how it draws (`chart_kind`): bar, line, donut, area, pie, stacked or scatter. */\n  chartKind: string | null;\n  /** Chart: what it measures per group (`chart_measure`): count, sum or avg. */\n  chartMeasure: string | null;\n  /** Pivot: the Field whose values are the columns; chart: the Field whose values are a stacked bar's series (`column_field`). */\n  columnField: string | null;\n  /** Pivot: what each cell measures (`pivot_measure`): count, sum, avg, min or max. */\n  pivotMeasure: string | null;\n  /** Scatter chart: the number Field along the bottom (`x_field`). */\n  xField: string | null;\n  dateField: string | null;\n  /** Timeline: where a record's bar starts (`start_field`). */\n  startField: string | null;\n  /** Calendar and timeline: where a record ends (`end_field`). */\n  endField: string | null;\n  imageField: string | null;\n  /** Map: the address, place or latitude Field that puts a record on the map (`map_field`). */\n  mapField: string | null;\n  /** Map: the longitude Field, when `mapField` is a latitude Field (`map_lng_field`). */\n  mapLngField: string | null;\n  /** Org chart: the link Field to the same table that says who a record reports to (`parent_field`). */\n  parentField: string | null;\n  /** Swipe: the Field each answer is written to (`answer_field`). */\n  answerField: string | null;\n  /** Swipe: the Field holding when a card is asked (`condition_field`). */\n  conditionField: string | null;\n  sorts: ViewSortKey[];\n  ruleId: string | null;\n  isDefault: boolean;\n  /** Personal: only the person who made the view lists it. False = collaborative (everyone with the table). */\n  personal: boolean;\n  /** The named section of the view list this view sits under, or null. */\n  section: string | null;\n  /** Where the view sits in the view list among its section's views (lowest first), or null = unplaced. */\n  position: number | null;\n  presentation: P;\n  movedFrom: Record<string, unknown> | null;\n}\n\n// The layouts a stored view reads back as; one the store does not keep yet reads as a grid. A\n// saved timeline read back as \"grid\" was the reload that lost it (FDT, 2026-10-03).\nconst KINDS: readonly string[] = STORE_KEPT_LAYOUTS;\n\n/** THE READER. A stored `definition` (and the row's flat `filters`) in, every declared key out. */\nexport function viewSettings<P = ViewPresentationDocument>(\n  definition: Record<string, unknown> | null | undefined,\n  rowFilters?: RecordFilter | null,\n  codec: ViewPresentationCodec<P> = plainCodec<P>(),\n): ViewSettings<P> {\n  const data = definition ?? {};\n  const text = (key: string): string | null => {\n    const v = data[key];\n    return typeof v === \"string\" && v !== \"\" ? v : null;\n  };\n  const layout = String(data[\"layout\"] ?? \"grid\");\n  const flat = rowFilters ?? (isObject(data[\"filters\"]) ? (data[\"filters\"] as RecordFilter) : null);\n  const moved = data[\"moved_from\"];\n  return {\n    layout: (KINDS as readonly string[]).includes(layout) ? (layout as ViewSettings<P>[\"layout\"]) : \"grid\",\n    filters: flat && Object.keys(flat).length > 0 ? flat : null,\n    where: isRule(data[\"where\"]) ? (data[\"where\"] as RuleExpression) : null,\n    groupField: text(\"group_field\"),\n    swimlaneField: text(\"swimlane_field\"),\n    collapsedColumns: Array.isArray(data[\"collapsed_columns\"])\n      ? (data[\"collapsed_columns\"] as unknown[]).filter((v) => [\"string\", \"number\", \"boolean\"].includes(typeof v)).map(String)\n      : [],\n    measure: text(\"measure\"),\n    chartKind: text(\"chart_kind\"),\n    chartMeasure: text(\"chart_measure\"),\n    columnField: text(\"column_field\"),\n    pivotMeasure: text(\"pivot_measure\"),\n    xField: text(\"x_field\"),\n    dateField: text(\"date_field\"),\n    startField: text(\"start_field\"),\n    endField: text(\"end_field\"),\n    imageField: text(\"image_field\"),\n    mapField: text(\"map_field\"),\n    mapLngField: text(\"map_lng_field\"),\n    parentField: text(\"parent_field\"),\n    answerField: text(\"answer_field\"),\n    conditionField: text(\"condition_field\"),\n    sorts: parseSorts(data[\"sorts\"]),\n    ruleId: text(\"rule_id\"),\n    isDefault: data[\"is_default\"] === true || data[\"is_default\"] === \"true\",\n    personal: data[\"personal\"] === true || data[\"personal\"] === \"true\",\n    section: text(\"section\"),\n    position: typeof data[\"position\"] === \"number\" && Number.isFinite(data[\"position\"]) ? (data[\"position\"] as number) : null,\n    presentation: codec.parse(data[\"presentation\"]),\n    movedFrom: isObject(moved) ? (moved as Record<string, unknown>) : null,\n  };\n}\n\n/** The settings as the spec names them — what `viewSettingsPatch` takes. */\nexport type ViewSettingsPatch<P = ViewPresentationDocument> = Partial<Omit<ViewSettings<P>, \"movedFrom\" | \"layout\">> & {\n  /** Any layout the package draws; one the store does not keep is not sent. */\n  layout?: string;\n};\n\n/**\n * THE KEYS ONE LAYOUT READS, and nothing else. A layout that does not use a key never sees it:\n * a calendar is not told the board's swimlanes, a board is not told the grid's pinned fields.\n */\nexport function viewSettingsFor<P extends object = ViewPresentationDocument>(settings: ViewSettings<P>, layout: ViewKeyLayout): Partial<ViewSettings<P>> {\n  const reads = new Set(viewKeysFor(layout));\n  const out: Partial<ViewSettings<P>> = { layout: settings.layout };\n  const take = <K extends keyof ViewSettings<P>>(key: K, path: string) => {\n    if (reads.has(path)) out[key] = settings[key];\n  };\n  take(\"filters\", \"filters\");\n  take(\"where\", \"where\");\n  take(\"groupField\", \"group_field\");\n  take(\"swimlaneField\", \"swimlane_field\");\n  take(\"collapsedColumns\", \"collapsed_columns\");\n  take(\"measure\", \"measure\");\n  take(\"chartKind\", \"chart_kind\");\n  take(\"chartMeasure\", \"chart_measure\");\n  take(\"columnField\", \"column_field\");\n  take(\"pivotMeasure\", \"pivot_measure\");\n  take(\"xField\", \"x_field\");\n  take(\"dateField\", \"date_field\");\n  take(\"startField\", \"start_field\");\n  take(\"endField\", \"end_field\");\n  take(\"imageField\", \"image_field\");\n  take(\"mapField\", \"map_field\");\n  take(\"mapLngField\", \"map_lng_field\");\n  take(\"parentField\", \"parent_field\");\n  take(\"answerField\", \"answer_field\");\n  take(\"conditionField\", \"condition_field\");\n  take(\"sorts\", \"sorts\");\n  take(\"ruleId\", \"rule_id\");\n  take(\"isDefault\", \"is_default\");\n  const p = settings.presentation;\n  const look = {} as P;\n  for (const [key, value] of Object.entries(p)) {\n    if (reads.has(`presentation.${key}`)) (look as Record<string, unknown>)[key] = value;\n  }\n  out.presentation = look;\n  return out;\n}\n\n/**\n * THE WRITER'S SHAPE. Only the keys a press changed; a cleared Field is `null` (the door removes\n * it); lists are sent whole. `presentation` is sent whole because the door judges it as one key.\n */\nexport function viewSettingsPatch<P = ViewPresentationDocument>(\n  patch: ViewSettingsPatch<P>,\n  codec: ViewPresentationCodec<P> = plainCodec<P>(),\n): Record<string, unknown> {\n  const out: Record<string, unknown> = {};\n  const field = (key: keyof ViewSettingsPatch<P>, path: string) => {\n    if (patch[key] !== undefined) out[path] = (patch[key] as string | null) || null;\n  };\n  // A layout the store does not keep yet is held for this visit, never sent (`STORE_KEPT_LAYOUTS`).\n  if (patch.layout !== undefined && storeKeepsLayout(patch.layout)) out[\"layout\"] = patch.layout;\n  field(\"groupField\", \"group_field\");\n  field(\"swimlaneField\", \"swimlane_field\");\n  field(\"measure\", \"measure\");\n  field(\"chartKind\", \"chart_kind\");\n  field(\"chartMeasure\", \"chart_measure\");\n  field(\"columnField\", \"column_field\");\n  field(\"pivotMeasure\", \"pivot_measure\");\n  field(\"xField\", \"x_field\");\n  field(\"dateField\", \"date_field\");\n  // Held for the visit until the store keeps them (`STORE_KEEPS_TIMELINE`).\n  if (STORE_KEEPS_TIMELINE) {\n    field(\"startField\", \"start_field\");\n    field(\"endField\", \"end_field\");\n  }\n  field(\"imageField\", \"image_field\");\n  field(\"mapField\", \"map_field\");\n  field(\"mapLngField\", \"map_lng_field\");\n  field(\"parentField\", \"parent_field\");\n  // Held for the visit until the store keeps them (`STORE_KEEPS_SWIPE`).\n  if (STORE_KEEPS_SWIPE) {\n    field(\"answerField\", \"answer_field\");\n    field(\"conditionField\", \"condition_field\");\n  }\n  field(\"ruleId\", \"rule_id\");\n  if (patch.collapsedColumns !== undefined) out[\"collapsed_columns\"] = patch.collapsedColumns ?? [];\n  if (patch.sorts !== undefined) out[\"sorts\"] = patch.sorts ?? [];\n  if (patch.where !== undefined) out[\"where\"] = patch.where ?? null;\n  if (patch.isDefault !== undefined) out[\"is_default\"] = patch.isDefault === true;\n  // Collaborative is the absence of the key: a view turned back to collaborative clears it.\n  if (patch.personal !== undefined) out[\"personal\"] = patch.personal === true ? true : null;\n  if (patch.position !== undefined) out[\"position\"] = typeof patch.position === \"number\" ? patch.position : null;\n  if (patch.section !== undefined) out[\"section\"] = patch.section && patch.section.trim() !== \"\" ? patch.section.trim() : null;\n  if (patch.presentation !== undefined) {\n    out[\"presentation\"] =\n      !patch.presentation || codec.isEmpty(patch.presentation) ? null : codec.toDocument(patch.presentation);\n  }\n  return out;\n}\n\nfunction isObject(raw: unknown): boolean {\n  return Boolean(raw) && typeof raw === \"object\" && !Array.isArray(raw);\n}\n\nfunction isRule(raw: unknown): boolean {\n  if (!isObject(raw)) return false;\n  const node = raw as { op?: unknown; args?: unknown };\n  return typeof node.op === \"string\" && Array.isArray(node.args);\n}\n\nfunction parseSorts(raw: unknown): ViewSortKey[] {\n  let list: unknown = raw;\n  if (typeof raw === \"string\") {\n    try {\n      list = raw.trim() === \"\" ? [] : JSON.parse(raw);\n    } catch {\n      return [];\n    }\n  }\n  if (!Array.isArray(list)) return [];\n  return list\n    .filter((s): s is { field: string; direction?: string } => isObject(s) && typeof (s as { field?: unknown }).field === \"string\")\n    .map((s) => ({ field: s.field, direction: s.direction === \"desc\" ? \"desc\" : \"asc\" }));\n}\n","// src/views/views.ts — @ai-matrx/records/views (headless; moved from records-ui views.ts, step 10 2026-10-08)\n// · SCR-6, SCR-7, SCR-N-6. The look (`presentation`) is a codec port (keys.ts); records-ui binds its grid look.\n//\n// A SAVED VIEW IS ONE ROW OF THE ONE SAVED-VIEW STORE, `platform.saved_view`\n// (chair ruling 2026-09-23, lane S0 ONE-SAVED-VIEW), read through `custom.views`\n// and written through `custom.view_declare` — the same door the digests, the\n// notify rules, the agent's boards, the grid's choices (G1/G7), the hand-set\n// order (G13) and the mover use. It owns its layout and REFERENCES its\n// membership rule.\n//\n// 🚨 THERE WERE TWO STORES (UI-CHAMPIONS-PLAN-ATTACK hole 1). Until S0 this bar\n// kept each view as a record of a package-owned `records_ui_view` Table in every\n// organization, beside `platform.saved_view`: a view the mover carried in never\n// reached the bar, a view saved in the bar was invisible to every subscription,\n// and a grid choice G1 kept had no screen that read it. The repair migration\n// `oneview_every_view_bar_view_moves_into_the_one_store.sql` moved every one of\n// those records into `platform.saved_view` UNDER THE SAME ID and archived the\n// Tables; nothing in this package reads or writes them any more.\n//\n// The split matters. A view does not carry a filter predicate of its own that a\n// screen re-implements in JavaScript: it names a Rule, and the STORE answers\n// who is in it (`custom.rule_members`). So the same view means the same thing\n// to a grid, to an export, to an agent and to the server. What the view owns\n// itself is presentation — which of the four layouts, which Field the kanban\n// columns come from, which Field the calendar reads, which Field the gallery\n// shows — because that is not data, it is how this person wants to look at it.\n//\n// The whole view is also a plain declarative object (`SavedViewSpec`), which is\n// what makes \"an agent writes the view in 45 seconds\" true: one `view_declare`\n// of one definition, and the person only tweaks.\n\nimport {\n  STORE_KEEPS_SWIPE,\n  STORE_KEEPS_TIMELINE,\n  plainPresentation,\n  storeKeepsLayout,\n  viewSettings,\n  viewSettingsPatch,\n  type ViewPresentationCodec,\n  type ViewPresentationDocument,\n} from \"./keys\";\nimport type { RecordsClient } from \"../core/client\";\nimport type { RecordFilter, RuleExpression, SavedViewRow, Uuid } from \"../core/index\";\nimport type { RecordsResult } from \"../results\";\n\nfunction plainCodec<P>(): ViewPresentationCodec<P> {\n  return plainPresentation as unknown as ViewPresentationCodec<P>;\n}\n\n/** The ways one saved view can be looked at (SCR-6; the timeline, lane VIEWS-AND-FIELDS TL). */\nexport const VIEW_LAYOUTS = [\"grid\", \"kanban\", \"calendar\", \"gallery\", \"timeline\", \"list\", \"chart\", \"map\", \"orgchart\", \"pivot\", \"swipe\"] as const;\nexport type ViewLayout = (typeof VIEW_LAYOUTS)[number];\n\nexport const LAYOUT_LABEL: Record<ViewLayout, string> = {\n  grid: \"Grid\",\n  kanban: \"Kanban\",\n  calendar: \"Calendar\",\n  gallery: \"Gallery\",\n  timeline: \"Timeline\",\n  list: \"List\",\n  chart: \"Chart\",\n  map: \"Map\",\n  orgchart: \"Org chart\",\n  pivot: \"Pivot\",\n  swipe: \"Swipe\",\n};\n\n\n/**\n * ─────────────────────────────────────────────────────────────────────────────\n * WHAT EACH LAYOUT NEEDS FROM THE TABLE, AND HOW THE SCREEN SUPPLIES IT\n * (lane DATA-V2-VIEWS-1, Arman 2026-09-28).\n *\n * THE DEFECT. A plain table opened as a Kanban said \"A kanban board needs a Field to make its\n * columns from … Add column, then Select — and it appears here.\" It told the person what to do\n * instead of doing it, and on an AI platform it offered no AI. The ruling: ONE primitive, used by\n * every view (`ViewNeeds`) — the empty state says in one plain sentence what is missing and what\n * pressing will do, offers \"Make it work\" (the column is declared through the store's\n * `custom.field_declare`, its key minted by the store, its name and choices editable before the\n * press) and \"Ask AI\" (the agent does it through the same door, held for the person's approval by\n * the organization's \"Agent changes to this organization's data\" setting).\n *\n * THE CENSUS — every layout this package draws, and what it reads:\n *   · grid      nothing.\n *   · kanban    a CHOICE column (its options become the board's columns). Blocking.\n *   · calendar  a DATE column (it places each record on a day). Blocking.\n *   · gallery   a FILE column for the card's picture. NOT blocking: the cards draw without one,\n *               so the offer sits above them instead of in place of them.\n *   · timeline  a DATE column each bar starts on (the calendar's `dateField`). Blocking.\n * `PAGE_VIEWS`' two extra values (dashboards, archived) read\n * nothing a table can lack. This package ships no map layout; the day it does,\n * `Record<ViewLayout, …>` below refuses to compile until the new layout names what it needs.\n */\nexport type ViewNeedKind = \"choice\" | \"date\" | \"file\";\n\nexport interface ViewNeed {\n  /** What the layout reads, as a kind a column declares (`offerableFields`). */\n  kind: ViewNeedKind;\n  /** The view key the made column is written onto, so the layout opens drawn by it. */\n  viewKey: \"groupField\" | \"dateField\" | \"imageField\";\n  /** True when the layout cannot draw at all without it (kanban, calendar). */\n  blocking: boolean;\n  /** The column the press makes, before the person edits it: its name, the store's word, its choices. */\n  starter: { label: string; type: \"select\" | \"datetime\" | \"attachment\"; options?: readonly string[] };\n  /** The table HAS columns this layout can use and none is chosen: the sentence over the picker. */\n  pick: string;\n  /** One plain sentence: what the table is missing (all a person who may not change it is told). */\n  missing: string;\n  /** One plain sentence: what pressing Make it work will do, with the column's name. */\n  does: (label: string) => string;\n  /** The sentence an agent is asked with — the same act, said in words. */\n  ask: (label: string, options: readonly string[]) => string;\n}\n\n/** A list of words as a person says it: \"To do, In progress and Done\". */\nexport function wordsList(words: readonly string[]): string {\n  const clean = words.map((w) => w.trim()).filter((w) => w !== \"\");\n  if (clean.length <= 1) return clean.join(\"\");\n  return `${clean.slice(0, -1).join(\", \")} and ${clean[clean.length - 1]}`;\n}\n\nexport const VIEW_NEEDS: Record<ViewLayout, ViewNeed | null> = {\n  grid: null,\n  // A list reads nothing a table can lack: rows, titled, grouped only when the person chooses.\n  list: null,\n  // A chart groups by any column or counts the whole table: it can always draw, and says how to group.\n  chart: null,\n  // A map and an org chart each need a column the person picks; with none they draw an honest picker (never a stand-in).\n  map: null,\n  orgchart: null,\n  // A pivot counts the whole table until a person picks its rows and columns: it can always draw.\n  pivot: null,\n  // A swipe deck asks every record as a card; it draws with the title alone and offers the answer column above the deck.\n  swipe: null,\n  kanban: {\n    kind: \"choice\",\n    viewKey: \"groupField\",\n    blocking: true,\n    starter: { label: \"Status\", type: \"select\", options: [\"To do\", \"In progress\", \"Done\"] },\n    pick: \"Pick the choice column the board's columns come from.\",\n    missing: \"This table has no choice column to make the board's columns from.\",\n    does: (label) => `Make it work adds a ${label} column with the choices below and groups the board by it.`,\n    ask: (label, options) =>\n      `Add a choice column called ${label} to this table${options.length > 0 ? ` with the choices ${wordsList(options)}` : \"\"}, then group the Kanban board by it.`,\n  },\n  calendar: {\n    kind: \"date\",\n    viewKey: \"dateField\",\n    blocking: true,\n    starter: { label: \"Date\", type: \"datetime\" },\n    pick: \"Pick the date column the calendar places records by.\",\n    missing: \"This table has no date column to place records on.\",\n    does: (label) => `Make it work adds a ${label} column and lays the calendar out by it.`,\n    ask: (label) => `Add a date column called ${label} to this table, then lay the Calendar out by it.`,\n  },\n  gallery: {\n    kind: \"file\",\n    viewKey: \"imageField\",\n    blocking: false,\n    starter: { label: \"Photo\", type: \"attachment\" },\n    pick: \"Pick the file column each card shows as its picture.\",\n    missing: \"The cards have no picture because this table has no file column.\",\n    does: (label) => `Make it work adds a ${label} column and shows it on each card.`,\n    ask: (label) => `Add a file column called ${label} to this table, then show it as the picture on each Gallery card.`,\n  },\n  timeline: {\n    kind: \"date\",\n    viewKey: \"dateField\",\n    blocking: true,\n    starter: { label: \"Start\", type: \"datetime\" },\n    pick: \"Pick the date column each bar starts on.\",\n    missing: \"This table has no date column to place records on.\",\n    does: (label) => `Make it work adds a ${label} column and lays the timeline out by it.`,\n    ask: (label) => `Add a date column called ${label} to this table, then lay the Timeline out by it.`,\n  },\n};\n\n/**\n * A NAME NO COLUMN OF THIS TABLE ALREADY HAS: the starter's own, else \"Status 2\", \"Status 3\"…\n * A table that already holds a text column called Status must not be refused the board.\n */\nexport function freeColumnName(wanted: string, taken: readonly string[]): string {\n  const held = new Set(taken.map((t) => t.trim().toLowerCase()));\n  const base = wanted.trim() === \"\" ? \"Column\" : wanted.trim();\n  if (!held.has(base.toLowerCase())) return base;\n  for (let n = 2; n < 100; n += 1) {\n    const next = `${base} ${n}`;\n    if (!held.has(next.toLowerCase())) return next;\n  }\n  return base;\n}\n\n/** One sort clause. The Field's key and a direction; nothing else is a sort. */\nexport interface ViewSort {\n  field: string;\n  direction: \"asc\" | \"desc\";\n}\n\n/** How a saved view is ordered: by hand, by its sort, or it never said (the same as sorted). */\nexport type ViewOrder = \"manual\" | \"sorted\" | null;\n\n/** The order word a stored definition carries. Only the two words the store writes are read. */\nexport function viewOrderOf(definition: Record<string, unknown> | null | undefined): ViewOrder {\n  const raw = definition?.[\"order\"];\n  return raw === \"manual\" ? \"manual\" : raw === \"sorted\" ? \"sorted\" : null;\n}\n\n/**\n * THE DECLARATIVE SPEC. An agent writes this whole object; a person tweaks it.\n * Every builder component in this package takes one of these as a prop.\n */\nexport interface SavedViewSpec<P = ViewPresentationDocument> {\n  name: string;\n  /** The Table this view looks at. */\n  subject: Uuid;\n  layout: ViewLayout;\n  /** Kanban: the Field whose value becomes a column. */\n  groupField?: string | null;\n  /**\n   * Kanban: a number Field to TOTAL under each column heading. It lives on the VIEW for\n   * the same reason the colors do — two people read one board two ways and neither\n   * reading is a fact about the records.\n   */\n  measure?: string | null;\n  /** Chart: how it draws: bar, line, donut, area, pie, stacked or scatter (`chart_kind`). */\n  chartKind?: string | null;\n  /** Chart: what it measures per group, `count`, `sum` or `avg` (`chart_measure`). */\n  chartMeasure?: string | null;\n  /** Pivot: the Field whose values are the columns; chart: a stacked bar's series (`column_field`). */\n  columnField?: string | null;\n  /** Pivot: what each cell measures: count, sum, avg, min or max (`pivot_measure`). */\n  pivotMeasure?: string | null;\n  /** Scatter chart: the number Field along the bottom (`x_field`). */\n  xField?: string | null;\n  /**\n   * Kanban: the Field whose values cut the board into SWIMLANES across the columns — a\n   * dispatcher's board by Status, one lane per Technician (S1-PRIME VIEW-KEYS). Never the\n   * column Field itself; the store refuses that.\n   */\n  swimlaneField?: string | null;\n  /** Kanban: the columns this view keeps shut to a strip, by the column's stored value. */\n  collapsedColumns?: string[];\n  /** Calendar: the Field that places a record in the month. */\n  dateField?: string | null;\n  /** Timeline: the Field a record's bar starts on (`start_field`). */\n  startField?: string | null;\n  /** Calendar and timeline: the Field a record ends on (`end_field`). */\n  endField?: string | null;\n  /** Gallery: the Field shown large on the card. */\n  imageField?: string | null;\n  /** Map: the address, place or latitude Field that puts a record on the map (`map_field`). */\n  mapField?: string | null;\n  /** Map: the longitude Field when `mapField` is a latitude Field (`map_lng_field`). */\n  mapLngField?: string | null;\n  /** Org chart: the link Field (to this same table) that says who a record reports to (`parent_field`). */\n  parentField?: string | null;\n  /** Swipe: the Field each answer is written to; a choice column's options are the answers (`answer_field`). */\n  answerField?: string | null;\n  /** Swipe: the Field holding when a card is asked — a condition over earlier cards (`condition_field`). */\n  conditionField?: string | null;\n  sorts?: ViewSort[];\n  /**\n   * HOW THE VIEW IS ORDERED (ORDER-FIX): `\"manual\"` — the positions a person set by hand ARE the\n   * view's sort, and it carries no `sorts`; `\"sorted\"` or null — by `sorts`. READ ONLY: the store\n   * writes \"manual\" only when the rows are placed (`custom.view_record_order_set`) and turns it\n   * off itself when a sort is saved, so no patch ever sends it (`viewSettingsPatch` does not).\n   */\n  order?: ViewOrder;\n  /**\n   * The membership Rule. The STORE decides who is in this view; this is a\n   * reference to its Rule record, never a predicate this package evaluates.\n   */\n  ruleId?: Uuid | null;\n  /**\n   * THE FLAT FILTER a digest or a notify rule wrote the view with — the one shape\n   * `custom.record_filter_sql` compiles, by Field KEY. A view saved in the bar has\n   * none; a view saved by `DigestScheduler` (\"where Status is Open\") does, and the\n   * grid and the board show exactly the records it names.\n   */\n  filters?: RecordFilter;\n  /**\n   * S2-PRIME — THE VIEW'S OWN QUESTION, as the condition builder writes it: the store's Rule\n   * shape `{op, args}`, ALL / ANY / NOT groups nested to any depth, Fields by id. Kept in the\n   * definition as `where` and asked of the store unchanged — the grid's list door, the board's\n   * headings and the dashboard's numbers compile it into the one WHERE clause\n   * (`custom.record_filter_sql`). Never stored under `filters`: that key is the flat map the\n   * digests and the notifier read, and they would refuse it by name.\n   */\n  where?: RuleExpression | null;\n  isDefault?: boolean;\n  /** PERSONAL (Airtable): only the person who made the view lists it. Absent/false = collaborative. */\n  personal?: boolean;\n  /** The named section of the view list this view sits under (VIEWS-AIRTABLE). Null/absent = unsectioned. */\n  section?: string | null;\n  /** Where the view sits in the view list among its section's views, lowest first (VIEWS-AIRTABLE). */\n  position?: number | null;\n  /**\n   * HOW THIS VIEW LOOKS — its colors, its per-column formats and its frozen\n   * column (`presentation.ts`).\n   *\n   * It lives on the VIEW and not on the Fields because two people read one\n   * table two ways and neither reading is a fact about the records; it lives on\n   * a RECORD, not a new column, because that is what makes it something an\n   * agent writes with the same `records` tool as everything else.\n   */\n  presentation?: P;\n}\n\n/**\n * A saved view as it comes back out of the store, with its row's own id.\n *\n * It carries no version: `custom.view_declare` MERGES one key at a time, so two\n * tabs pressing two different controls on one view both stand, and one control\n * pressed in both keeps the latest — how Airtable and Notion keep a view change.\n */\nexport interface SavedView<P = ViewPresentationDocument> extends SavedViewSpec<P> {\n  id: Uuid;\n  /** Where the view came from when it was moved in (the mover, the S0 repair), else null. */\n  movedFrom: Record<string, unknown> | null;\n}\n\n/** THE TABLE'S DEFAULT VIEW: the first view that says it is. */\nexport function defaultViewOf<V extends Pick<SavedView, \"isDefault\">>(views: readonly V[]): V | undefined {\n  return views.find((v) => v.isDefault);\n}\n\n/**\n * WHICH FIELD EACH LAYOUT CAN BE DRAWN FROM, decided from the FIELD'S OWN\n * DECLARATION and never from the values it happens to hold.\n *\n * A kanban makes columns from a choice: the Field whose value is one of a\n * closed set (FLD-5 / FLD-6 — a pick-list is a Table, and a select stores the\n * id of one of its records). Grouping by a free-text Field produces one column\n * per record, which is not a board. A calendar places a record in time, so it\n * needs a Field that holds a date.\n *\n * These two answers are here, beside the layouts, because the picker on the\n * screen and any agent writing a view spec must agree about what is offerable.\n */\nexport const LAYOUT_FIELD_KIND: Record<ViewLayout, ViewNeedKind | null> = {\n  grid: null,\n  kanban: \"choice\",\n  calendar: \"date\",\n  gallery: \"file\",\n  timeline: \"date\",\n  list: null,\n  chart: null,\n  map: null,\n  orgchart: null,\n  pivot: null,\n  swipe: null,\n};\n\n/**\n * ─────────────────────────────────────────────────────────────────────────────\n * WHICH VIEW A LINK NAMES — the address bar as a first-class control.\n *\n * 🚨 THE DEFECT THIS CLOSES (lane FRONT-DOOR, 2026-09-21; VERIFIER-8 HIGH-2).\n * `/data/<table>?view=kanban` returned 200 and rendered THE GRID. The\n * switcher was there, the four buttons worked, and the parameter was read by\n * nobody — so a person who bookmarked a board, or sent one to a colleague, got\n * a grid, and nothing on the screen said the view had been dropped. A link that\n * does not land is the inbox-link defect (`activeRecordId`) and the dashboard\n * defect (`activeDashboardId`) for the third time, so this is the same shape of\n * fix: the URL names it, the page opens on it, and the URL FOLLOWS the person\n * when they pick another.\n *\n * The dashboards are a fifth value and not a special case: to the person, \"the\n * dashboard\" is one of the ways to look at this table, and a link to it has to\n * work like a link to the board.\n */\n/**\n * 🚨 `archived` IS THE SIXTH VALUE, AND IT IS NOT A SPECIAL CASE EITHER (lane\n * FIX-10A-ARCHIVE, 2026-09-22; VERIFIER-10 F4).\n *\n * Archiving a record used to be a ONE-WAY DOOR: the grid's row action soft-\n * deletes correctly — `deleted_at` set, version bumped, nothing removed — and\n * then no screen anywhere in the platform could bring it back. The store's\n * `custom.record_restore` was there the whole time and did exactly the right\n * thing; nothing reached it, because every read door answers live rows only.\n *\n * So the archive is a WAY OF LOOKING AT THIS TABLE, like the board and the\n * dashboards, reached by the same row of buttons and named by the same\n * `?view=` parameter — never a Trash area of the app somebody has to know\n * exists, and never a per-table screen. Every Table inherits it the moment it\n * is in this list.\n */\nexport const PAGE_VIEWS = [...VIEW_LAYOUTS, \"dashboards\", \"archived\"] as const;\nexport type PageView = (typeof PAGE_VIEWS)[number];\n\nexport const PAGE_VIEW_LABEL: Record<PageView, string> = {\n  ...LAYOUT_LABEL,\n  dashboards: \"Dashboards\",\n  archived: \"Archived\",\n};\n\n/**\n * THE WORDS A LINK MAY USE. The canonical token first; the rest are what a\n * person or an agent actually types, because a link that dies on \"board\" when\n * the button says \"Kanban\" is the same dead link with better spelling.\n */\nconst PAGE_VIEW_SPELLINGS: Record<string, PageView> = {\n  grid: \"grid\",\n  table: \"grid\",\n  rows: \"grid\",\n  list: \"list\",\n  kanban: \"kanban\",\n  board: \"kanban\",\n  pipeline: \"kanban\",\n  calendar: \"calendar\",\n  month: \"calendar\",\n  schedule: \"calendar\",\n  gallery: \"gallery\",\n  cards: \"gallery\",\n  timeline: \"timeline\",\n  gantt: \"timeline\",\n  chart: \"chart\",\n  graph: \"chart\",\n  map: \"map\",\n  locations: \"map\",\n  orgchart: \"orgchart\",\n  \"org-chart\": \"orgchart\",\n  org: \"orgchart\",\n  hierarchy: \"orgchart\",\n  pivot: \"pivot\",\n  crosstab: \"pivot\",\n  \"cross-tab\": \"pivot\",\n  pivottable: \"pivot\",\n  swipe: \"swipe\",\n  deck: \"swipe\",\n  quiz: \"swipe\",\n  survey: \"swipe\",\n  questions: \"swipe\",\n  dashboards: \"dashboards\",\n  dashboard: \"dashboards\",\n  charts: \"dashboards\",\n  archived: \"archived\",\n  archive: \"archived\",\n  // The grid's row action says \"Delete\" and the store soft-deletes, so the word\n  // a person types is as likely to be the one the button used as the one this\n  // view is called. Both land in the same place; neither dies.\n  deleted: \"archived\",\n  trash: \"archived\",\n  removed: \"archived\",\n};\n\n/**\n * What a `?view=` value means, or `null` when it means nothing here.\n *\n * `null` is NOT \"show the grid\": the caller is expected to say that the link\n * named something this table has no view for, because silently substituting a\n * different view is exactly the defect above wearing a parser.\n */\nexport function pageViewFromParam(raw: string | null | undefined): PageView | null {\n  if (typeof raw !== \"string\") return null;\n  const token = raw.trim().toLowerCase();\n  if (token === \"\") return null;\n  return PAGE_VIEW_SPELLINGS[token] ?? null;\n}\n\n/** The sentence a link that named a view nobody has says. Never silent. */\nexport function unknownViewLine(raw: string): string {\n  return (\n    `The link asked for a view called “${raw}”, which this table has no view for, so you are looking at ` +\n    `${PAGE_VIEW_LABEL.grid}. The views this table has are ` +\n    `${PAGE_VIEWS.map((v) => PAGE_VIEW_LABEL[v]).join(\", \")} — pick one above and the address follows it.`\n  );\n}\n\n/**\n * THE SPEC AS THE ONE DEFINITION `platform.saved_view` HOLDS — the keys\n * `custom.view_declare` documents, by Field KEY. `subject` is not in it: the door\n * takes the Table as its own argument and writes `table_id` itself.\n */\nexport function viewDocument<P = ViewPresentationDocument>(spec: SavedViewSpec<P>, codec: ViewPresentationCodec<P> = plainCodec<P>()): Record<string, unknown> {\n  const out: Record<string, unknown> = {\n    // A layout the store does not keep yet is not sent: the view is saved as a grid (`STORE_KEPT_LAYOUTS`).\n    layout: storeKeepsLayout(spec.layout) ? spec.layout : \"grid\",\n    sorts: spec.sorts ?? [],\n    is_default: spec.isDefault === true,\n  };\n  if (spec.groupField) out[\"group_field\"] = spec.groupField;\n  if (spec.swimlaneField) out[\"swimlane_field\"] = spec.swimlaneField;\n  if (spec.collapsedColumns && spec.collapsedColumns.length > 0) out[\"collapsed_columns\"] = spec.collapsedColumns;\n  if (spec.measure) out[\"measure\"] = spec.measure;\n  if (spec.chartKind) out[\"chart_kind\"] = spec.chartKind;\n  if (spec.chartMeasure) out[\"chart_measure\"] = spec.chartMeasure;\n  if (spec.columnField) out[\"column_field\"] = spec.columnField;\n  if (spec.pivotMeasure) out[\"pivot_measure\"] = spec.pivotMeasure;\n  if (spec.xField) out[\"x_field\"] = spec.xField;\n  if (spec.dateField) out[\"date_field\"] = spec.dateField;\n  if (STORE_KEEPS_TIMELINE && spec.startField) out[\"start_field\"] = spec.startField;\n  if (STORE_KEEPS_TIMELINE && spec.endField) out[\"end_field\"] = spec.endField;\n  if (spec.imageField) out[\"image_field\"] = spec.imageField;\n  if (spec.mapField) out[\"map_field\"] = spec.mapField;\n  if (spec.mapLngField) out[\"map_lng_field\"] = spec.mapLngField;\n  if (spec.parentField) out[\"parent_field\"] = spec.parentField;\n  if (STORE_KEEPS_SWIPE && spec.answerField) out[\"answer_field\"] = spec.answerField;\n  if (STORE_KEEPS_SWIPE && spec.conditionField) out[\"condition_field\"] = spec.conditionField;\n  if (spec.ruleId) out[\"rule_id\"] = spec.ruleId;\n  if (spec.where) out[\"where\"] = spec.where;\n  if (spec.personal === true) out[\"personal\"] = true;\n  if (spec.section && spec.section.trim() !== \"\") out[\"section\"] = spec.section.trim();\n  if (typeof spec.position === \"number\") out[\"position\"] = spec.position;\n  if (spec.presentation && !codec.isEmpty(spec.presentation)) {\n    out[\"presentation\"] = codec.toDocument(spec.presentation);\n  }\n  return out;\n}\n\n/**\n * One row of `custom.views` back into the spec a screen and an agent both read — THROUGH THE ONE\n * ACCESSOR (`viewSettings`, viewKeys.ts), so every layout sees every declared key the same way.\n */\nexport function viewFromRow<P = ViewPresentationDocument>(row: SavedViewRow, codec: ViewPresentationCodec<P> = plainCodec<P>()): SavedView<P> {\n  const data = (row.definition ?? {}) as Record<string, unknown>;\n  const k = viewSettings(data, row.filters && Object.keys(row.filters).length > 0 ? row.filters : null, codec);\n  const tableFromDefinition = typeof data[\"table_id\"] === \"string\" && data[\"table_id\"] !== \"\" ? (data[\"table_id\"] as string) : null;\n  return {\n    id: row.view_id,\n    name: row.name || \"Untitled view\",\n    subject: (row.table_id ?? tableFromDefinition ?? \"\") as Uuid,\n    layout: k.layout,\n    groupField: k.groupField,\n    swimlaneField: k.swimlaneField,\n    collapsedColumns: k.collapsedColumns,\n    measure: k.measure,\n    chartKind: k.chartKind,\n    chartMeasure: k.chartMeasure,\n    columnField: k.columnField,\n    pivotMeasure: k.pivotMeasure,\n    xField: k.xField,\n    dateField: k.dateField,\n    startField: k.startField,\n    endField: k.endField,\n    imageField: k.imageField,\n    mapField: k.mapField,\n    mapLngField: k.mapLngField,\n    parentField: k.parentField,\n    answerField: k.answerField,\n    conditionField: k.conditionField,\n    sorts: k.sorts,\n    order: viewOrderOf(data),\n    ruleId: k.ruleId,\n    ...(k.filters ? { filters: k.filters } : {}),\n    where: k.where,\n    // The older table's own default view, carried in by the mover, IS this table's default —\n    // the mover wrote the row's column, which `custom.views` does not return. Read as anything\n    // else, the page would seed a second \"All records\" beside it and open on that.\n    isDefault: k.isDefault || k.movedFrom?.[\"kind\"] === \"default_view\",\n    personal: k.personal,\n    section: k.section,\n    position: k.position,\n    presentation: k.presentation,\n    movedFrom: k.movedFrom,\n  };\n}\n\n/**\n * SAVE ONE NEW VIEW of a Table — the bar's \"New view\" and an agent's seed spec.\n * One `view_declare` with no `view_id`; the answer is the new view's id.\n */\nexport async function declareView<P = ViewPresentationDocument>(\n  client: Pick<RecordsClient, \"viewDeclare\">,\n  spec: SavedViewSpec<P>,\n  codec: ViewPresentationCodec<P> = plainCodec<P>(),\n): Promise<RecordsResult<Uuid>> {\n  return client.viewDeclare({\n    table_id: spec.subject,\n    spec: {\n      name: spec.name,\n      ...(spec.filters ? { filters: spec.filters } : {}),\n      definition: viewDocument(spec, codec),\n    },\n  });\n}\n\n/**\n * WRITE A CHANGE ONTO A SAVED VIEW, AND KEEP IT.\n *\n * `custom.view_declare` with the view's id MERGES: only the keys in `patch` are\n * written, a key cleared to null is removed, and everything the patch did not\n * name — the grid's own choices, a hand-set order, where the view was moved from,\n * a color set in another tab — stays exactly as it was (S0, 2026-09-23: the door\n * used to rebuild the whole definition from what one press sent).\n *\n * There is no version to be stale against (VERIFIER-15 M4 is closed by the shape,\n * not by a retry): a saved view is a person's own arrangement of a table, and\n * their latest press on a control is the one that stands. A refusal — the view\n * was removed, or belongs to a table this person cannot open — is handed back for\n * the page to say through the one notice.\n */\nexport async function saveViewPatch<P = ViewPresentationDocument>(\n  client: Pick<RecordsClient, \"viewDeclare\">,\n  tableId: Uuid,\n  viewId: Uuid,\n  patch: Partial<SavedViewSpec<P>>,\n  codec: ViewPresentationCodec<P> = plainCodec<P>(),\n): Promise<RecordsResult<Uuid>> {\n  const definition = viewPatchDocument(patch, codec);\n  const renamed = patch.name !== undefined && patch.name.trim() !== \"\";\n  const refiltered = patch.filters !== undefined;\n  return client.viewDeclare({\n    table_id: tableId,\n    spec: {\n      view_id: viewId,\n      ...(renamed ? { name: patch.name!.trim() } : {}),\n      ...(refiltered ? { filters: patch.filters ?? null } : {}),\n      definition,\n    },\n  });\n}\n\n/**\n * A PARTIAL change to a saved view, as the definition keys the door merges. Only\n * the keys the caller actually changed are sent; a Field cleared (a board with no\n * \"Group by\") is sent as `null`, which the door removes.\n */\nexport function viewPatchDocument<P = ViewPresentationDocument>(\n  patch: Partial<SavedViewSpec<P>>,\n  codec: ViewPresentationCodec<P> = plainCodec<P>(),\n): Record<string, unknown> {\n  const { name: _name, subject: _subject, filters: _filters, ...keys } = patch;\n  return viewSettingsPatch(keys, codec);\n}\n\n/**\n * A LOOK AT A TABLE NEVER CHANGES HOW IT OPENS (lane VIEW-SWITCH-NOT-DESIGNATION, VERIFIER-21).\n *\n * On production the owner pressed Kanban, then Calendar, and the office member's table opened in\n * the Calendar: every layout press was saved onto the DEFAULT view, which is how the table opens\n * for everyone. The table's default view's `layout` and `isDefault` are its DESIGNATION, changed\n * only by an editor's deliberate \"Make this the default\" (`designateView`); the store refuses them\n * through `view_declare` by name. So a press on the default view carries every other key it\n * changed — a board's grouping, a calendar's date, a color — and never those two.\n */\nexport function viewPatchFor<S extends { layout?: unknown; isDefault?: boolean }>(\n  view: { isDefault?: boolean },\n  patch: Partial<S>,\n): Partial<S> {\n  if (!view.isDefault) return patch;\n  const { layout: _layout, isDefault: _isDefault, ...kept } = patch;\n  return kept as Partial<S>;\n}\n\n/** The one words for the explicit designation, with the layout it would make the default. */\nexport function makeDefaultLabel(layoutLabel: string): string {\n  return `Make ${layoutLabel} the default`;\n}\n\n/**\n * MAKE THIS THE DEFAULT — the ONE designation door (`custom.view_designate`, editor on the table).\n * `layout` is the layout this table should open in for everyone: one of the layouts the store keeps. The view\n * becomes the table's only default.\n */\nexport async function designateView(\n  client: Pick<RecordsClient, \"viewDesignate\">,\n  tableId: Uuid,\n  viewId: Uuid,\n  layout: string | null,\n): Promise<RecordsResult<Uuid>> {\n  return client.viewDesignate({ table_id: tableId, view_id: viewId, layout });\n}\n\n// ── VIEWS-AIRTABLE (2026-10-10): sections of the view list ──────────────────────────────────────────────\n\n/** A section of the view list with the views under it, in the list's order. `name` null = unsectioned. */\nexport interface ViewSection<V extends Pick<SavedView, \"section\"> = SavedView> {\n  name: string | null;\n  views: V[];\n}\n\n/**\n * THE VIEW LIST, GROUPED. Unsectioned views come first (the table's default among them), then each\n * section in the order its first view appears. A section exists while a view is in it.\n */\nexport function groupViewsBySection<V extends Pick<SavedView, \"section\"> & { position?: number | null }>(views: readonly V[]): ViewSection<V>[] {\n  const loose: V[] = [];\n  const named = new Map<string, V[]>();\n  for (const v of views) {\n    const name = v.section?.trim();\n    if (!name) loose.push(v);\n    else named.set(name, [...(named.get(name) ?? []), v]);\n  }\n  // Placed views first, lowest position first; the rest keep the order the store gave (a stable sort).\n  const placed = (list: V[]) => [...list].sort((a, b) => (a.position ?? Number.MAX_SAFE_INTEGER) - (b.position ?? Number.MAX_SAFE_INTEGER));\n  return [...(loose.length > 0 ? [{ name: null, views: placed(loose) }] : []), ...[...named].map(([name, list]) => ({ name, views: placed(list) }))];\n}\n\n/** The names of the sections the list has, in order. */\nexport function sectionNames(views: readonly Pick<SavedView, \"section\">[]): string[] {\n  return groupViewsBySection(views).flatMap((s) => (s.name === null ? [] : [s.name]));\n}\n\n/** Whether a section name is one the store keeps: 1 to 60 characters after trimming. */\nexport function sectionNameOk(raw: string): boolean {\n  const n = raw.trim();\n  return n.length > 0 && n.length <= 60;\n}\n\n/**\n * RENAME OR DELETE A SECTION: one `view_declare` per view under it. `to` null deletes the section (its\n * views go back to the unsectioned list; no view is archived). Stops at the first refusal and hands it back.\n */\nexport async function reassignSection(\n  client: Pick<RecordsClient, \"viewDeclare\">,\n  tableId: Uuid,\n  views: readonly Pick<SavedView, \"id\" | \"section\">[],\n  from: string,\n  to: string | null,\n): Promise<RecordsResult<number>> {\n  let moved = 0;\n  for (const v of views.filter((x) => x.section?.trim() === from)) {\n    const written = await saveViewPatch(client, tableId, v.id, { section: to });\n    if (!written.ok) return written;\n    moved += 1;\n  }\n  return { ok: true, data: moved };\n}\n\n/** One write of a drag: the view, and the keys that change (`section` null = out of every section). */\nexport interface ViewDropWrite {\n  id: Uuid;\n  section?: string | null;\n  position: number;\n}\n\n/** The droppable id of a section's empty space (the end of its list); \"\" is the unsectioned list. */\nexport const sectionDropId = (name: string | null): string => `section:${name ?? \"\"}`;\n\n/**\n * WHAT DROPPING A VIEW WRITES. `overId` is a view (it takes that view's place) or a section's space\n * (`sectionDropId`; it goes to the end of that section). Every view in the target section is given its\n * place 0..n-1 so the list stays what the person saw; only views whose place or section changed are written.\n * Pure: the bar sends each write through `saveViewPatch`.\n */\nexport function planViewDrop<V extends Pick<SavedView, \"id\" | \"section\"> & { position?: number | null }>(\n  views: readonly V[],\n  activeId: string,\n  overId: string,\n): ViewDropWrite[] {\n  const groups = groupViewsBySection(views);\n  const from = groups.find((g) => g.views.some((v) => v.id === activeId));\n  const moving = from?.views.find((v) => v.id === activeId);\n  if (!from || !moving || activeId === overId) return [];\n  let target: ViewSection<V> | undefined;\n  let index: number;\n  if (overId.startsWith(\"section:\")) {\n    const raw = overId.slice(\"section:\".length).trim();\n    const name = raw === \"\" ? null : raw;\n    target = groups.find((g) => g.name === name) ?? { name, views: [] };\n    index = target.views.filter((v) => v.id !== activeId).length;\n  } else {\n    target = groups.find((g) => g.views.some((v) => v.id === overId));\n    if (!target) return [];\n    const without = target.views.filter((v) => v.id !== activeId);\n    const overAt = without.findIndex((v) => v.id === overId);\n    const wasAt = target.views.findIndex((v) => v.id === activeId);\n    const overWas = target.views.findIndex((v) => v.id === overId);\n    // Dragging down inside a list lands after the one it was dropped on; up (or from another list), before it.\n    index = wasAt !== -1 && wasAt < overWas ? overAt + 1 : overAt;\n  }\n  const list = target.views.filter((v) => v.id !== activeId);\n  list.splice(index, 0, moving);\n  const sectionChanged = (target.name ?? null) !== (moving.section?.trim() || null);\n  const writes: ViewDropWrite[] = [];\n  list.forEach((v, i) => {\n    if (v.id === activeId) writes.push({ id: v.id as Uuid, ...(sectionChanged ? { section: target!.name } : {}), position: i });\n    else if (v.position !== i) writes.push({ id: v.id as Uuid, position: i });\n  });\n  // The dragged view changes only when it moved: same section and same place writes nothing.\n  return writes.filter((w) => w.id !== activeId || sectionChanged || moving.position !== w.position);\n}\n","// src/views/look.ts — @ai-matrx/records/views · A PERSON'S OWN LOOK AT A SHARED VIEW, HEADLESS\n//\n// (Moved from records-ui `viewLook.ts`, step 10, 2026-10-08.) How a person looks at a shared view (its grouping,\n// date field, sort, filter, presentation, layout) is HER look: the store keeps one per (person, view) through\n// `custom.view_look_set` / `view_look_read`, never written onto the view row. The view changes only when she\n// saves to it. This file is the look's shape: the keys a look may hold, how it reads back, how it lays over the\n// view, and what \"Save to view\" sends. The presentation half reads through the same codec port as the view.\n\nimport type { RecordsClient } from \"../core/client\";\nimport type { Uuid } from \"../core/index\";\nimport type { RecordsResult } from \"../results\";\nimport { plainPresentation, viewSettings, viewSettingsPatch, type ViewPresentationCodec, type ViewPresentationDocument } from \"./keys\";\nimport { VIEW_LAYOUTS, viewPatchFor, type SavedView, type SavedViewSpec, type ViewLayout } from \"./views\";\n\nconst plain = <P>() => plainPresentation as unknown as ViewPresentationCodec<P>;\n\n/**\n * WHAT A LOOK MAY HOLD — how a person looks, never what the view is: not its name, not whether it is the default,\n * not its Rule, not the flat filters the digests read, not the order the store writes.\n */\nexport type ViewLook<P = ViewPresentationDocument> = Partial<\n  Pick<\n    SavedViewSpec<P>,\n    | \"layout\"\n    | \"groupField\"\n    | \"swimlaneField\"\n    | \"collapsedColumns\"\n    | \"measure\"\n    | \"dateField\"\n    | \"startField\"\n    | \"endField\"\n    | \"imageField\"\n    | \"mapField\"\n    | \"mapLngField\"\n    | \"parentField\"\n    | \"answerField\"\n    | \"conditionField\"\n    | \"sorts\"\n    | \"where\"\n    | \"presentation\"\n  >\n>;\n\nconst LOOK_KEYS = [\n  \"layout\",\n  \"groupField\",\n  \"swimlaneField\",\n  \"collapsedColumns\",\n  \"measure\",\n  \"dateField\",\n  \"startField\",\n  \"endField\",\n  \"imageField\",\n  \"mapField\",\n  \"mapLngField\",\n  \"parentField\",\n  \"answerField\",\n  \"conditionField\",\n  \"sorts\",\n  \"where\",\n  \"presentation\",\n] as const satisfies ReadonlyArray<keyof ViewLook>;\n\n/** Only the look's own keys of a press — a name, a default, a Rule or an order is never a look. */\nexport function lookPart<P = ViewPresentationDocument>(patch: Partial<SavedViewSpec<P>>): ViewLook<P> {\n  const out: ViewLook<P> = {};\n  for (const key of LOOK_KEYS) {\n    if (patch[key] !== undefined) (out as Record<string, unknown>)[key] = patch[key];\n  }\n  return out;\n}\n\n/** The look as the definition keys the store keeps (`view_look_set`); a cleared key is null. */\nexport function lookDocument<P = ViewPresentationDocument>(look: ViewLook<P>, codec: ViewPresentationCodec<P> = plain<P>()): Record<string, unknown> {\n  return viewSettingsPatch<P>(look, codec);\n}\n\n/** A kept look back into the spec's words. Only the keys it holds; a null key is \"none, for me\". */\nexport function lookFromDocument<P = ViewPresentationDocument>(\n  doc: Record<string, unknown> | null | undefined,\n  codec: ViewPresentationCodec<P> = plain<P>(),\n): ViewLook<P> {\n  const data = doc ?? {};\n  const read = viewSettings<P>(data, undefined, codec);\n  const out: ViewLook<P> = {};\n  const has = (key: string) => Object.prototype.hasOwnProperty.call(data, key);\n  if (has(\"layout\") && (VIEW_LAYOUTS as readonly string[]).includes(String(data[\"layout\"]))) {\n    out.layout = data[\"layout\"] as ViewLayout;\n  }\n  if (has(\"group_field\")) out.groupField = read.groupField;\n  if (has(\"swimlane_field\")) out.swimlaneField = read.swimlaneField;\n  if (has(\"collapsed_columns\")) out.collapsedColumns = read.collapsedColumns;\n  if (has(\"measure\")) out.measure = read.measure;\n  if (has(\"date_field\")) out.dateField = read.dateField;\n  if (has(\"start_field\")) out.startField = read.startField;\n  if (has(\"end_field\")) out.endField = read.endField;\n  if (has(\"image_field\")) out.imageField = read.imageField;\n  if (has(\"map_field\")) out.mapField = read.mapField;\n  if (has(\"map_lng_field\")) out.mapLngField = read.mapLngField;\n  if (has(\"parent_field\")) out.parentField = read.parentField;\n  if (has(\"answer_field\")) out.answerField = read.answerField;\n  if (has(\"condition_field\")) out.conditionField = read.conditionField;\n  if (has(\"sorts\")) out.sorts = read.sorts;\n  if (has(\"where\")) out.where = read.where;\n  if (has(\"presentation\")) out.presentation = codec.parse(data[\"presentation\"]);\n  return out;\n}\n\n/** THE VIEW AS THIS PERSON SEES IT: the saved view, with her look laid over it. */\nexport function applyLook<P = ViewPresentationDocument>(view: SavedView<P>, look: ViewLook<P> | null | undefined): SavedView<P> {\n  if (!look) return view;\n  return { ...view, ...look } as SavedView<P>;\n}\n\n/** Whether the look shows anything the view does not — which is when \"Save to view\" means something. */\nexport function lookDiffers<P = ViewPresentationDocument>(view: SavedView<P>, look: ViewLook<P> | null | undefined): boolean {\n  if (!look) return false;\n  const shown = applyLook(view, look);\n  return LOOK_KEYS.some((key) => look[key] !== undefined && JSON.stringify(shown[key] ?? null) !== JSON.stringify(view[key] ?? null));\n}\n\n/**\n * WHAT \"SAVE TO VIEW\" SENDS, and what stays the person's own afterwards. The default view's layout is the table's\n * designation (`viewPatchFor`): it is never saved here, so a look's layout on the default view stays her look.\n */\nexport function saveToViewPlan<P = ViewPresentationDocument>(\n  view: SavedView<P>,\n  look: ViewLook<P>,\n): { patch: Partial<SavedViewSpec<P>>; left: ViewLook<P> | null } {\n  const patch = viewPatchFor(view, look) as Partial<SavedViewSpec<P>>;\n  const left: ViewLook<P> = {};\n  if (look.layout !== undefined && patch.layout === undefined && look.layout !== view.layout) left.layout = look.layout;\n  return { patch, left: Object.keys(left).length > 0 ? left : null };\n}\n\n/** The caller's own looks at every view of a table, by view id. */\nexport async function readLooks<P = ViewPresentationDocument>(\n  client: Pick<RecordsClient, \"viewLookRead\">,\n  tableId: Uuid,\n  codec: ViewPresentationCodec<P> = plain<P>(),\n): Promise<RecordsResult<Record<string, ViewLook<P>>>> {\n  const answered = await client.viewLookRead({ table_id: tableId });\n  if (!answered.ok) return answered;\n  const out: Record<string, ViewLook<P>> = {};\n  for (const [viewId, row] of Object.entries(answered.data ?? {})) {\n    out[viewId] = lookFromDocument(row?.look ?? null, codec);\n  }\n  return { ok: true, data: out };\n}\n\n/** Keep the whole look (null: \"Reset to view\"). The shared view is never written. */\nexport async function keepLook<P = ViewPresentationDocument>(\n  client: Pick<RecordsClient, \"viewLookSet\">,\n  tableId: Uuid,\n  viewId: Uuid,\n  look: ViewLook<P> | null,\n  codec: ViewPresentationCodec<P> = plain<P>(),\n): Promise<RecordsResult<Record<string, unknown> | null>> {\n  const doc = look ? lookDocument(look, codec) : null;\n  return client.viewLookSet({ table_id: tableId, view_id: viewId, look: doc && Object.keys(doc).length > 0 ? doc : null });\n}\n","// src/views/bind.ts — @ai-matrx/records/views · ONE CODEC, BOUND ONCE\n//\n// A host that draws its own look (records-ui's grid presentation) binds its codec here once and re-exports the\n// bound doors under the same names. There is ONE definition of each door — this package's — and the host's names\n// are bindings of it, never a second body (architecture guard: no same-name twin across records and records-ui).\n\nimport type { RecordFilter, SavedViewRow, Uuid } from \"../core/index\";\nimport type { RecordsClient } from \"../core/client\";\nimport { viewSettings, viewSettingsPatch, type ViewPresentationCodec, type ViewSettingsPatch } from \"./keys\";\nimport { declareView, saveViewPatch, viewDocument, viewFromRow, viewPatchDocument, type SavedViewSpec } from \"./views\";\nimport { keepLook, lookDocument, lookFromDocument, readLooks, type ViewLook } from \"./look\";\n\n/** Every door of a saved view and a person's look, with the host's presentation codec bound. */\nexport function bindViewCodec<P>(codec: ViewPresentationCodec<P>) {\n  return {\n    viewSettings: (definition: Record<string, unknown> | null | undefined, rowFilters?: RecordFilter | null) =>\n      viewSettings<P>(definition, rowFilters, codec),\n    viewSettingsPatch: (patch: ViewSettingsPatch<P>) => viewSettingsPatch<P>(patch, codec),\n    viewDocument: (spec: SavedViewSpec<P>) => viewDocument<P>(spec, codec),\n    viewFromRow: (row: SavedViewRow) => viewFromRow<P>(row, codec),\n    declareView: (client: Pick<RecordsClient, \"viewDeclare\">, spec: SavedViewSpec<P>) => declareView<P>(client, spec, codec),\n    saveViewPatch: (client: Pick<RecordsClient, \"viewDeclare\">, tableId: Uuid, viewId: Uuid, patch: Partial<SavedViewSpec<P>>) =>\n      saveViewPatch<P>(client, tableId, viewId, patch, codec),\n    viewPatchDocument: (patch: Partial<SavedViewSpec<P>>) => viewPatchDocument<P>(patch, codec),\n    lookDocument: (look: ViewLook<P>) => lookDocument<P>(look, codec),\n    lookFromDocument: (doc: Record<string, unknown> | null | undefined) => lookFromDocument<P>(doc, codec),\n    readLooks: (client: Pick<RecordsClient, \"viewLookRead\">, tableId: Uuid) => readLooks<P>(client, tableId, codec),\n    keepLook: (client: Pick<RecordsClient, \"viewLookSet\">, tableId: Uuid, viewId: Uuid, look: ViewLook<P> | null) =>\n      keepLook<P>(client, tableId, viewId, look, codec),\n  };\n}\n","// src/aggregate.ts — @ai-matrx/records\n//\n// THE EIGHTH VERB (AGT-N-8). `custom.record_aggregate` groups, buckets, filters\n// and measures INSIDE the read door's own query: the aggregate node sits above\n// the join to `custom.query_visible_ids`, so a chart is computed over the rows\n// this principal may see and the rest are never fetched at all.\n//\n// That is why a chart in this platform is not \"read everything, then sum in the\n// browser\". Summing in the browser would either read rows a person may not see\n// or quietly under-count them, and both of those are a screen telling a lie.\n\nimport type { HiddenFieldNotice } from \"./record\";\nimport type { RuleExpression } from \"./rule\";\n\n/** The measures the store offers. Asked of `custom.agg_operations()` at run time too. */\nexport type AggregateOperation =\n  | \"count\" | \"sum\" | \"avg\" | \"min\" | \"max\"\n  /** GRID-PRIMITIVES G1: the summary bar's other four. Blank = no value, JSON null or \"\". */\n  | \"median\" | \"filled\" | \"empty\" | \"unique\"\n  /**\n   * Notion's calculation row (Spaces N6): the share of the rows asked with no value / a value, as a\n   * percent 0..100 (NULL over no rows); and the RANGE, largest minus smallest (a date column: the days\n   * between its earliest and latest moment).\n   */\n  | \"percent_empty\" | \"percent_filled\" | \"range\";\n\n/** The periods a date Field can be bucketed into (`custom.agg_buckets()`). */\nexport type AggregateBucket = \"day\" | \"week\" | \"month\" | \"quarter\" | \"year\";\n\n/**\n * A HALF-OPEN MOMENT WINDOW: `from` is inclusive, `to` is exclusive. Half-open\n * is the only shape that makes \"September\" and \"October\" meet exactly once —\n * an inclusive `to` either double-counts the boundary moment or drops it,\n * depending on the reader, and both of those are a chart telling a lie.\n */\nexport interface AggregateWindow {\n  from?: string | null;\n  to?: string | null;\n}\n\n/**\n * ONE FILTER VALUE, as `custom.record_aggregate` and `custom.dashboard_run`\n * both read it: a SCALAR is an equality, and an OBJECT is a window. It is not\n * `unknown` on purpose — a filter value the store cannot read is a refusal a\n * caller should get from the compiler, not from the database.\n */\nexport type AggregateFilter = string | number | boolean | null | AggregateWindow;\n\n/**\n * 🚨 THE STORE'S ONE FILTER SHAPE, AND THE ONLY NAME FOR IT.\n *\n * An object of Field key -> value. A scalar is an equality, `null` is UNSET\n * (the third state of a tick box), an object is a half-open time window.\n *\n * It is not the aggregate's private shape and never was. `platform.saved_view`\n * has carried exactly this as `definition -> 'filters'` across five live\n * surface keys since DOOR-18; `custom.view_declare` writes it;\n * `custom.agg_view_admits` reads it to decide whether a change belongs to a\n * saved view; `custom.record_aggregate` takes it as `p_filter` to COMPUTE a\n * dashboard number; and `custom.read_records_matching` takes it to OPEN the\n * rows behind that number. One `custom.record_filter_sql` in the database turns\n * it into SQL for the last two, so the number and the rows cannot disagree.\n *\n * Invent a second one and a chart can compute a total whose drill-through\n * lands somewhere else, which is the only way a drill-through can lie.\n */\nexport type RecordFilter = Record<string, AggregateFilter>;\n\n/**\n * S2-PRIME FILTER-GROUPS — A READ DOOR'S QUESTION, IN EITHER OF ITS TWO SHAPES.\n *\n * The flat `RecordFilter` above (field key → scalar / `null` / window, AND only) is what\n * dashboards, drill-throughs and the notifier carry. A `RuleExpression` — `{op, args}`, ALL / ANY /\n * NOT groups nested to any depth, fields by id — is what the condition builder, a view's own\n * filter and every membership Rule speak. `custom.record_filter_sql(org, table, filter)` turns\n * EITHER into the one WHERE clause the grid (`list`), the aggregate and the board all use, so the\n * three can never disagree about which records a view holds.\n */\nexport type StoreFilter = RecordFilter | RuleExpression;\n\n/**\n * Is this filter a Rule expression? The store's own test (`custom.filter_is_rule`): an object\n * whose `op` is a word and which carries `args`.\n */\nexport function isRuleFilter(filter: unknown): filter is RuleExpression {\n  if (!filter || typeof filter !== \"object\" || Array.isArray(filter)) return false;\n  const node = filter as { op?: unknown; args?: unknown };\n  return typeof node.op === \"string\" && Array.isArray(node.args);\n}\n\n/** One measure. `count` counts rows and needs no Field; the rest read one. */\nexport interface AggregateMeasure {\n  op: AggregateOperation;\n  /** The Field's key. Required for every operation except `count`. */\n  key?: string;\n}\n\n/**\n * One row of an aggregate: which group it is, what each measure came to, and\n * how many records it was worked out from. The measure keys are the store's\n * own (`count`, `sum_amount`, `avg_amount`, …), never renamed on the way out.\n */\n/**\n * One group's key, as the column holds it (CHAIR-SHEET-STORE b): a number column's key is a number, a\n * yes/no column's true/false, a date its ISO text, a date period its first moment, everything else text.\n */\nexport type AggregateGroupValue = string | number | boolean | null;\n\nexport interface AggregateRow {\n  groups: Record<string, AggregateGroupValue>;\n  measures: Record<string, number | null>;\n  /**\n   * AGG-WITHHELD — a measure over a column this reader may not read is `null` in `measures` (the\n   * \"no value\" every number reader already handles) and its reason rides HERE by measure name: the\n   * same notice a withheld cell carries (`reason`, `needs`, `or`) plus the store's own sentence in\n   * `says`. The store never errors a read for a withheld column; it says so. A question that\n   * GROUPS or FILTERS by such a column answers one row with every measure null and `row_count` 0.\n   * Absent when nothing was withheld.\n   */\n  withheld?: Record<string, HiddenFieldNotice & { says?: string; label?: string; field_key?: string }>;\n  row_count: number;\n  /**\n   * S3 — present only when the question carried a comparison. The same group\n   * in the PRIOR window: a bucket is matched by its position in its own window\n   * (week 1 of September beside week 1 of August), so `prior_groups` names the\n   * prior bucket's own date. `null` when the prior window had no such group.\n   */\n  prior_groups?: Record<string, string | null> | null;\n  /** The prior window's measures, keyed exactly like `measures`. */\n  prior_measures?: Record<string, number | null> | null;\n  prior_row_count?: number | null;\n  /** Every measure now and before, the change, and the change as a percent of before. */\n  delta?: Record<string, AggregateDelta> | null;\n  /** The two windows this row was worked out over, and the calendar that cut them. */\n  compare?: AggregateCompareWindows | null;\n  /**\n   * S3 — a compared, bucketed row's POSITION in its window (0 = the first\n   * bucket). A row the current window has not reached yet has a position and\n   * no current bucket, so a chart names it \"Week 6\" rather than inventing a date.\n   */\n  position?: number | null;\n}\n\n/**\n * S3 — WHAT A PERIOD IS COMPARED AGAINST (`custom.agg_compare_kinds()`).\n * `previous_period` is the period before, of the same length (August before\n * September; an explicit window shifted back by its own length);\n * `same_period_last_year`; `range` is a fixed `baseline`.\n */\nexport type AggregateCompareKind = \"previous_period\" | \"same_period_last_year\" | \"range\";\n\n/**\n * S3 — ONE COMPARISON, as `custom.record_aggregate(p_compare)` and a\n * dashboard block's `compare` both take it. The current window is either the\n * calendar `period` holding `at` (default: now, in the organization's time\n * zone) or an explicit `from`/`to`. A date alone (\"2026-09-01\") is that local\n * day in the organization's time zone.\n */\nexport interface AggregateCompare {\n  against?: AggregateCompareKind;\n  /** The date Field the period runs along. Defaults to the bucket's key. */\n  key?: string;\n  period?: AggregateBucket;\n  at?: string;\n  from?: string;\n  to?: string;\n  /** Compare the part of the period that has happened (\"month to date\"). */\n  to_date?: boolean;\n  /** The fixed period `range` compares against. Half-open: `to` is excluded. */\n  baseline?: { from: string; to: string };\n}\n\n/** One measure now and before. `change_pct` is null when before was nothing or zero. */\nexport interface AggregateDelta {\n  current: number | null;\n  prior: number | null;\n  change: number | null;\n  change_pct: number | null;\n}\n\n/**\n * S3 — THE TWO WINDOWS the store actually ran, as local ISO moments with the\n * organization's offset (\"2026-09-01T00:00:00-07:00\"), and the calendar that\n * cut them. A screen labels the comparison from THIS, never from its own clock.\n */\nexport interface AggregateCompareWindows {\n  key: string;\n  against: AggregateCompareKind;\n  period: AggregateBucket | null;\n  to_date: boolean;\n  time_zone: string;\n  week_start: string;\n  /** The bucket grain the windows were counted in, when the question had a bucket. */\n  grain: AggregateBucket | null;\n  /** How many buckets the current window holds — what a target's pace is shared over. */\n  bucket_count: number | null;\n  window: { from: string; to: string };\n  prior_window: { from: string; to: string };\n  /** On a row from `recordAggregate`: that row's bucket position (see `AggregateRow.position`). */\n  position?: number | null;\n}\n\n/** The measure key the store answers with, so a chart can find its own series. */\nexport function measureKey(measure: AggregateMeasure): string {\n  return measure.op === \"count\" ? \"count\" : `${measure.op}_${measure.key ?? \"\"}`;\n}\n\n/**\n * THE QUESTION, AS A STABLE STRING — key-sorted JSON of a `RecordFilter`.\n *\n * A React parent that rebuilds `{ status: \"Cancelled\" }` on every render hands\n * a NEW object every time, and a hook that depends on the object re-reads the\n * whole page on every render forever. Depending on this instead means the page\n * is re-read exactly when the QUESTION changed, which is what a person means.\n *\n * Nested window objects are sorted too, so `{from, to}` and `{to, from}` are\n * one question. `undefined` and an empty filter are both `\"{}\"` — the caller\n * asked nothing, and there is only one way to ask nothing.\n */\nexport function stableFilterKey(filter: StoreFilter | null | undefined): string {\n  if (!filter) return \"{}\";\n  // A Rule expression is ORDERED — the evaluator asks its arguments in order — so its own JSON is\n  // already the question; only a flat map's keys need sorting.\n  if (isRuleFilter(filter)) return JSON.stringify(filter);\n  const keys = Object.keys(filter).sort();\n  if (keys.length === 0) return \"{}\";\n  const parts = keys.map((key) => {\n    const value = filter[key];\n    if (value !== null && typeof value === \"object\") {\n      const window = value as AggregateWindow;\n      return `${JSON.stringify(key)}:{\"from\":${JSON.stringify(window.from ?? null)},\"to\":${JSON.stringify(window.to ?? null)}}`;\n    }\n    return `${JSON.stringify(key)}:${JSON.stringify(value ?? null)}`;\n  });\n  return `{${parts.join(\",\")}}`;\n}\n\n/**\n * AGG-WITHHELD — the store's answer, with the withheld state lifted out of `measures`.\n * `custom.record_aggregate` puts a withheld measure's notice under `measures._withheld`\n * (null beside it); no consumer should ever meet that key among the numbers, so the one door\n * that reads the answer moves it to `row.withheld` and zeroes a count the store left out.\n */\nexport function liftWithheld(rows: AggregateRow[]): AggregateRow[] {\n  // HONEST-REFUSALS 2 — the store says the withheld explanation ONCE, on the first row's `measures._withheld`\n  // (older answers repeated it on every row). Whichever row carries it, every row of the answer gets the same\n  // `withheld`, so a total or a chart reads `row.withheld` exactly as before.\n  let shared: unknown;\n  for (const row of rows) {\n    const m = ((row.measures ?? {}) as Record<string, unknown>)[\"_withheld\"];\n    if (m !== undefined && m !== null && typeof m === \"object\") {\n      shared = m;\n      break;\n    }\n  }\n  return rows.map((row) => {\n    const measures = (row.measures ?? {}) as Record<string, unknown>;\n    const own = measures[\"_withheld\"];\n    const marker = own !== undefined && own !== null && typeof own === \"object\" ? own : shared;\n    const rowCount = (row.row_count as number | null) ?? 0;\n    if (marker === undefined || marker === null || typeof marker !== \"object\") {\n      return rowCount === row.row_count ? row : { ...row, row_count: rowCount };\n    }\n    const { _withheld: _drop, ...rest } = measures;\n    const withheld: NonNullable<AggregateRow[\"withheld\"]> = {};\n    for (const [name, raw] of Object.entries(marker as Record<string, unknown>)) {\n      const m = (raw ?? {}) as { withheld?: Partial<HiddenFieldNotice>; says?: string; label?: string; field_key?: string };\n      withheld[name] = {\n        reason: m.withheld?.reason ?? null,\n        needs: m.withheld?.needs ?? null,\n        or: m.withheld?.or ?? null,\n        ...(m.says ? { says: m.says } : {}),\n        ...(m.label ? { label: m.label } : {}),\n        ...(m.field_key ? { field_key: m.field_key } : {}),\n      };\n    }\n    return { ...row, measures: rest as Record<string, number | null>, withheld, row_count: rowCount };\n  });\n}\n\n/**\n * ROLLUP-FILTER (2026-10-18) — SEVERAL VALUES FOR ONE COLUMN, IN A FLAT FILTER.\n *\n * Beside a single value (`{status: \"Paid\"}`) and a window (`{paid_on: {relative: \"this_month\"}}`), a\n * column of a flat filter (a roll-up's `config.filter`, a saved view's filters) takes\n *   - an any-of list   `{status: [\"Sent\", \"Overdue\"]}`              (the store's list branch, has_any)\n *   - a not-in form    `{status: {not: [\"Draft\", \"Cancelled\"]}}`    (one word works too; list question is_not)\n * Each word is a choice's key or label, any case. This is the ONE reading of that grammar for the TypeScript\n * twins of `custom.record_filter_sql` (the memory world, the template checker); the store's own is the SQL.\n * A blank cell is none of the words, so a not-in form keeps it.\n */\nexport type FilterWords = { mode: \"any\" | \"none\"; words: string[] };\n\n/** `{not: ...}` / a list as the words it asks about, or `null` when the value is neither (a scalar, a window, null). */\nexport function filterWordsOf(want: unknown): FilterWords | null {\n  const strings = (v: unknown): string[] | null => {\n    if (typeof v === \"string\" || typeof v === \"number\" || typeof v === \"boolean\") return [String(v)];\n    if (Array.isArray(v) && v.every((x) => typeof x === \"string\" || typeof x === \"number\" || typeof x === \"boolean\")) return v.map(String);\n    return null;\n  };\n  if (Array.isArray(want)) {\n    const words = strings(want);\n    return words ? { mode: \"any\", words } : null;\n  }\n  if (want && typeof want === \"object\") {\n    const o = want as Record<string, unknown>;\n    const keys = Object.keys(o);\n    if (keys.length === 1 && keys[0] === \"not\") {\n      const words = strings(o[\"not\"]);\n      return words ? { mode: \"none\", words } : null;\n    }\n  }\n  return null;\n}\n\n/**\n * Does a cell (one value, a list, or nothing) satisfy an any-of / not-in question? `aliases` maps a word to the other\n * words that name the same choice (its key and label), so a filter written with the key reads a cell kept as the label.\n */\nexport function cellMatchesWords(cell: unknown, q: FilterWords, aliases?: (word: string) => readonly string[]): boolean {\n  const cellWords = (Array.isArray(cell) ? cell : [cell])\n    .filter((x) => x !== null && x !== undefined && String(x).trim() !== \"\")\n    .map((x) => String(x).trim().toLowerCase());\n  const asked = new Set(q.words.flatMap((w) => [w, ...(aliases?.(w) ?? [])]).map((w) => w.trim().toLowerCase()));\n  const hit = cellWords.some((w) => asked.has(w));\n  return q.mode === \"any\" ? hit : !hit;\n}\n","// RELATIVE DAYS ARE THE READER'S DAYS (ADVERSARIAL-11 F3).\n//\n// A saved view that says \"Today\", \"Overdue\" or \"This week\" (`{ due_on: { relative: \"today\" } }`, or a\n// `within` Rule node) used to be worked out in the DATABASE from the reader's SAVED zone. A saved zone\n// that was one browser behind (a new device, a trip, the first page of a session read before the zone\n// was written) made a person in Los Angeles at 23:05 see tomorrow's items under \"Today\".\n//\n// The client now works the window out itself, in the zone it is actually being read in (the person's\n// zone the host mirrored with `setReadersTimeZone`, else this browser's), and sends exact bounds. The\n// database still accepts and works out a relative window it is handed (older callers keep working);\n// this only means a relative window never reaches it from this client.\n//\n// Mirrors custom.relative_window_for_reader: same kinds, same half-open [from, to), same week start.\n\nexport const RELATIVE_DAY_KINDS = [\n  \"today\", \"tomorrow\", \"yesterday\",\n  \"this_week\", \"next_week\", \"last_week\",\n  \"this_month\", \"next_month\", \"last_month\",\n  \"before_today\", \"next_days\", \"past_days\",\n] as const;\n\nexport type RelativeDayKind = (typeof RELATIVE_DAY_KINDS)[number];\n\nlet readersZone: string | null = null;\n\nfunction validZone(z: unknown): z is string {\n  if (typeof z !== \"string\" || !z.trim()) return false;\n  try {\n    new Intl.DateTimeFormat(\"en-US\", { timeZone: z });\n    return true;\n  } catch {\n    return false;\n  }\n}\n\n/** The zone the host reads this person's day in (their saved zone, or the browser's while it follows). `null` clears. */\nexport function setReadersTimeZone(zone: string | null | undefined): void {\n  readersZone = validZone(zone) ? zone : null;\n}\n\n/** The zone a relative day is worked out in: the host's mirrored zone, else this browser's, else UTC. */\nexport function readersTimeZone(): string {\n  if (readersZone) return readersZone;\n  try {\n    const device = Intl.DateTimeFormat().resolvedOptions().timeZone;\n    if (validZone(device)) return device;\n  } catch {\n    /* fall through */\n  }\n  return \"UTC\";\n}\n\n/** Calendar parts of `at` on a wall clock in `zone`. */\nfunction partsIn(zone: string, at: Date): { y: number; m: number; d: number } {\n  const p = new Intl.DateTimeFormat(\"en-US\", { timeZone: zone, year: \"numeric\", month: \"2-digit\", day: \"2-digit\" }).formatToParts(at);\n  const n = (t: string) => Number(p.find((x) => x.type === t)?.value ?? 0);\n  return { y: n(\"year\"), m: n(\"month\"), d: n(\"day\") };\n}\n\nconst ymd = (t: Date) =>\n  `${t.getUTCFullYear()}-${String(t.getUTCMonth() + 1).padStart(2, \"0\")}-${String(t.getUTCDate()).padStart(2, \"0\")}`;\n\n/** The instant at which the wall clock in `zone` first reads midnight of civil day `day` (a UTC-midnight Date standing for it). */\nfunction midnightInstant(zone: string, day: Date): Date {\n  const y = day.getUTCFullYear();\n  const m = day.getUTCMonth();\n  const d = day.getUTCDate();\n  // Start from the UTC guess, then correct by how far the zone's wall clock is from the wanted one (twice: DST-safe).\n  let guess = Date.UTC(y, m, d);\n  for (let i = 0; i < 3; i += 1) {\n    const f = new Intl.DateTimeFormat(\"en-US\", {\n      timeZone: zone, year: \"numeric\", month: \"2-digit\", day: \"2-digit\", hour: \"2-digit\", minute: \"2-digit\", second: \"2-digit\", hourCycle: \"h23\",\n    }).formatToParts(new Date(guess));\n    const n = (t: string) => Number(f.find((x) => x.type === t)?.value ?? 0);\n    const wall = Date.UTC(n(\"year\"), n(\"month\") - 1, n(\"day\"), n(\"hour\"), n(\"minute\"), n(\"second\"));\n    const diff = Date.UTC(y, m, d) - wall;\n    if (diff === 0) break;\n    guess += diff;\n  }\n  return new Date(guess);\n}\n\nexport interface RelativeWindowOptions {\n  zone?: string;\n  now?: Date;\n  /** First day of the week, Sunday 0 ... Saturday 6. Monday (1) by default, the organization knob's default. */\n  weekStart?: number;\n  /** A moment column (created_at, a datetime): the window is the reader's local midnights as instants. */\n  instants?: boolean;\n}\n\n/**\n * One relative window as exact bounds, half-open [from, to), or `null` when `window` is not a relative\n * window this knows (it is then left for the store to judge). A date-only column gets calendar days.\n */\nexport function relativeWindowBounds(window: unknown, opts: RelativeWindowOptions = {}): { from?: string; to?: string } | null {\n  if (!window || typeof window !== \"object\" || Array.isArray(window)) return null;\n  const w = window as { relative?: unknown; n?: unknown };\n  const kind = w.relative as RelativeDayKind;\n  if (typeof kind !== \"string\" || !(RELATIVE_DAY_KINDS as readonly string[]).includes(kind)) return null;\n  const zone = opts.zone && validZone(opts.zone) ? opts.zone : readersTimeZone();\n  const n = typeof w.n === \"number\" && Number.isFinite(w.n) ? Math.min(Math.max(Math.trunc(w.n), 0), 3660) : null;\n  if ((kind === \"next_days\" || kind === \"past_days\") && n === null) return null;\n\n  const p = partsIn(zone, opts.now ?? new Date());\n  const t = new Date(Date.UTC(p.y, p.m - 1, p.d));\n  const add = (base: Date, days: number) => new Date(base.getTime() + days * 86_400_000);\n  const first = opts.weekStart !== undefined ? ((opts.weekStart % 7) + 7) % 7 : 1;\n  const ws = add(t, -((t.getUTCDay() - first + 7) % 7));\n  const ms = new Date(Date.UTC(p.y, p.m - 1, 1));\n  const month = (k: number) => new Date(Date.UTC(ms.getUTCFullYear(), ms.getUTCMonth() + k, 1));\n\n  let from: Date | undefined;\n  let to: Date | undefined;\n  switch (kind) {\n    case \"today\": from = t; to = add(t, 1); break;\n    case \"tomorrow\": from = add(t, 1); to = add(t, 2); break;\n    case \"yesterday\": from = add(t, -1); to = t; break;\n    case \"this_week\": from = ws; to = add(ws, 7); break;\n    case \"next_week\": from = add(ws, 7); to = add(ws, 14); break;\n    case \"last_week\": from = add(ws, -7); to = ws; break;\n    case \"this_month\": from = ms; to = month(1); break;\n    case \"next_month\": from = month(1); to = month(2); break;\n    case \"last_month\": from = month(-1); to = ms; break;\n    case \"before_today\": to = t; break;\n    case \"next_days\": from = t; to = add(t, n!); break;\n    case \"past_days\": from = add(t, -n!); to = t; break;\n  }\n  const out = (d: Date | undefined) =>\n    d === undefined ? undefined : opts.instants ? midnightInstant(zone, d).toISOString().replace(/\\.\\d{3}Z$/, \"Z\") : ymd(d);\n  const f = out(from);\n  const e = out(to);\n  return { ...(f === undefined ? {} : { from: f }), ...(e === undefined ? {} : { to: e }) };\n}\n\n/** What the filter needs to know about a column to cut its window: the key and whether it holds moments. */\nexport interface RelativeFieldLookup {\n  byKey(key: string): { instants: boolean } | null;\n  byId(id: string): { instants: boolean } | null;\n}\n\n/** A lookup over the table's Fields (a moment column is `created_at` / `updated_at` or `config.kind === \"datetime\"`). */\nexport function lookupFromFields(fields: ReadonlyArray<{ id: string; key: string; config?: Record<string, unknown> | null }>): RelativeFieldLookup {\n  const info = (f: { key: string; config?: Record<string, unknown> | null }) => ({\n    instants: f.key === \"created_at\" || f.key === \"updated_at\" || f.config?.[\"kind\"] === \"datetime\",\n  });\n  return {\n    byKey: (key) => {\n      const f = fields.find((x) => x.key === key);\n      return f ? info(f) : key === \"created_at\" || key === \"updated_at\" ? { instants: true } : null;\n    },\n    byId: (id) => {\n      const f = fields.find((x) => x.id === id);\n      return f ? info(f) : null;\n    },\n  };\n}\n\n/** Does this filter hold a relative window anywhere? (Cheap test so a filter without one never loads Fields.) */\nexport function holdsRelativeDays(filter: unknown): boolean {\n  if (!filter || typeof filter !== \"object\") return false;\n  if (Array.isArray(filter)) return filter.some(holdsRelativeDays);\n  const o = filter as Record<string, unknown>;\n  if (typeof o[\"relative\"] === \"string\") return true;\n  return Object.values(o).some(holdsRelativeDays);\n}\n\n/**\n * The filter with every relative window worked out for THIS reader, now. Flat filters (`{ due_on: { relative } }`) and\n * Rule `within` nodes, at any depth. A window it cannot place (an unknown column, an unknown kind) is left as it was.\n * Never mutates its input.\n */\nexport function resolveRelativeDays(filter: unknown, lookup: RelativeFieldLookup, opts: Omit<RelativeWindowOptions, \"instants\"> = {}): unknown {\n  if (!holdsRelativeDays(filter)) return filter;\n  const walk = (node: unknown, flatTop: boolean): unknown => {\n    if (Array.isArray(node)) return node.map((x) => walk(x, false));\n    if (!node || typeof node !== \"object\") return node;\n    const o = node as Record<string, unknown>;\n    if (o[\"op\"] === \"within\" && Array.isArray(o[\"args\"]) && o[\"args\"].length === 2) {\n      const [a, b] = o[\"args\"] as Array<Record<string, unknown> | undefined>;\n      const id = a && typeof a[\"field\"] === \"string\" ? (a[\"field\"] as string) : null;\n      const win = b && typeof b === \"object\" ? (b[\"const\"] as unknown) : null;\n      const col = id ? lookup.byId(id) : null;\n      const bounds = col ? relativeWindowBounds(win, { ...opts, instants: col.instants }) : null;\n      return bounds ? { ...o, args: [a, { const: bounds }] } : node;\n    }\n    const out: Record<string, unknown> = {};\n    for (const [k, v] of Object.entries(o)) {\n      if (flatTop && v && typeof v === \"object\" && !Array.isArray(v) && typeof (v as { relative?: unknown }).relative === \"string\") {\n        const col = lookup.byKey(k);\n        const bounds = col ? relativeWindowBounds(v, { ...opts, instants: col.instants }) : null;\n        out[k] = bounds ?? v;\n      } else {\n        out[k] = walk(v, false);\n      }\n    }\n    return out;\n  };\n  const isRule = !!filter && typeof filter === \"object\" && typeof (filter as { op?: unknown }).op === \"string\";\n  return walk(filter, !isRule);\n}\n\n/** `\"sunday\"` .. `\"saturday\"` as `Date.getUTCDay()` counts; anything else is Monday, the knob's default. */\nexport function weekStartIndexOf(word: string | null | undefined): number {\n  const days = [\"sunday\", \"monday\", \"tuesday\", \"wednesday\", \"thursday\", \"friday\", \"saturday\"];\n  const at = days.indexOf(String(word ?? \"\").trim().toLowerCase());\n  return at < 0 ? 1 : at;\n}\n"],"mappings":"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","names":["plainCodec"]}