@ai-matrx/records 0.72.14 → 0.72.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/dist/app-table/index.d.cts +3 -3
  3. package/dist/app-table/index.d.ts +3 -3
  4. package/dist/core/index.d.cts +5 -5
  5. package/dist/core/index.d.ts +5 -5
  6. package/dist/{declareTable-Br8pE4fr.d.cts → declareTable-CLvpMdgJ.d.cts} +2 -2
  7. package/dist/{declareTable-DM6z1tc-.d.ts → declareTable-DY3oN4rq.d.ts} +2 -2
  8. package/dist/index.d.cts +3 -3
  9. package/dist/index.d.ts +3 -3
  10. package/dist/memory/index.cjs +2912 -0
  11. package/dist/memory/index.cjs.map +1 -0
  12. package/dist/memory/index.d.cts +126 -0
  13. package/dist/memory/index.d.ts +126 -0
  14. package/dist/memory/index.js +2889 -0
  15. package/dist/memory/index.js.map +1 -0
  16. package/dist/{ports-DKBvsoya.d.cts → ports-DKOk7AT2.d.cts} +1 -1
  17. package/dist/{ports-Bhu2Q3V0.d.ts → ports-Df3VghxK.d.ts} +1 -1
  18. package/dist/{table-kind-D6Lz7ebE.d.ts → table-kind-CD9B1vtx.d.ts} +1 -1
  19. package/dist/{table-kind-D6VOew74.d.cts → table-kind-e-g5kGXV.d.cts} +1 -1
  20. package/dist/templates/index.cjs +44 -17
  21. package/dist/templates/index.cjs.map +1 -1
  22. package/dist/templates/index.d.cts +18 -1176
  23. package/dist/templates/index.d.ts +18 -1176
  24. package/dist/templates/index.js +44 -17
  25. package/dist/templates/index.js.map +1 -1
  26. package/dist/{validate-QtFxMmJc.d.ts → types-Ba11aOEO.d.ts} +1 -42
  27. package/dist/{validate-DUSrx-9E.d.cts → types-BtEKp3ot.d.cts} +1 -42
  28. package/dist/types-DxVoKKpL.d.ts +1186 -0
  29. package/dist/types-dlj1-2t2.d.cts +1186 -0
  30. package/dist/use-cases/index.d.cts +3 -2
  31. package/dist/use-cases/index.d.ts +3 -2
  32. package/dist/validate-CMb7R_ke.d.cts +44 -0
  33. package/dist/validate-E-g4LAZ6.d.ts +44 -0
  34. package/package.json +13 -1
@@ -1,1178 +1,11 @@
1
- import { p as DashboardBlockKind, h as AggregateMeasure, e as AggregateBucket, q as AggregateFilter, r as SubscriptionCadence, s as AggregateOperation, t as RecordsDataSource } from '../ports-Bhu2Q3V0.js';
2
- import { d as UseCaseField, o as UseCaseRow, f as UseCaseFormField, i as UseCaseNotificationTrigger, N as NotificationChannel, U as UseCase, p as UseCaseTable, e as UseCaseForm, m as UseCaseProvenance, l as UseCaseProblem } from '../validate-QtFxMmJc.js';
1
+ import { A as AgentSnapshotRow, T as TemplateSpec, a as TemplateTable, S as SharedBlockId, C as CapabilityWord, b as TemplateField, c as TemplateAgent, d as TemplateAutomation, e as TemplateBooking, f as TemplateChecklist, g as TemplateDashboard, h as TemplateDigest, i as TemplateDocument, j as TemplateDrillDown, k as TemplateDimensions, l as TemplateForm, m as TemplateNotification, n as TemplatePortal, o as TemplateRowAction, p as TemplateStageRules, q as TemplateView, r as TemplateMergeBinding, s as TemplateTryIt, t as TemplateWorkflow, u as TemplateFootprint } from '../types-DxVoKKpL.js';
2
+ export { v as CAPABILITY_WORDS, w as CATALOGUE_QUOTAS, x as CATALOGUE_STATUSES, y as CHOICE_COLORS, z as CatalogueRow, B as CatalogueStatus, D as ChoiceColor, E as ConfidentialLevel, F as ConfidentialRequest, G as DEFAULT_TEMPLATE_AGENT, H as ENTITY_REFERENCE_KINDS, I as INDUSTRY_GROUPS, J as IndustryGroup, R as RELATIVE_DATE, K as RetiredId, L as SHARED_BLOCKS, M as SHARED_BLOCK_IDS, N as STRENGTHS, O as SharedBlock, P as SharedBlockField, Q as SharedBlockUse, U as Strength, V as TABLE_KERNEL_ID, W as TEACHES_FEATURES, X as TEMPLATE_AUDIENCES, Y as TEMPLATE_EXTRA_KINDS, Z as TEMPLATE_JOBS, _ as TEMPLATE_REFERENCE_DATE, $ as TEMPLATE_SPEC_VERSION, a0 as TEMPLATE_VIEW_KINDS, a1 as TeachesFeature, a2 as TemplateAgentQuestion, a3 as TemplateAgentVariable, a4 as TemplateAudience, a5 as TemplateBookingWindow, a6 as TemplateCalendarView, a7 as TemplateChecklistStep, a8 as TemplateConfidential, a9 as TemplateConfidentialReader, aa as TemplateDashboardBlock, ab as TemplateDimensionOverride, ac as TemplateDrillPath, ad as TemplateExtra, ae as TemplateExtraAgent, af as TemplateExtraAgentVariable, ag as TemplateExtraKind, ah as TemplateFormField, ai as TemplateFoundation, aj as TemplateGalleryView, ak as TemplateGridView, al as TemplateGuideStep, am as TemplateJob, an as TemplateKanbanView, ao as TemplateMeasureOverride, ap as TemplatePortalTable, aq as TemplateProvenance, ar as TemplateSource, as as TemplateTableSettings, at as TemplateTimelineView, au as TemplateViewKind, av as TemplateViewSort, aw as UseCaseSingulars, ax as WalkAction, ay as WalkAssertion, az as WalkImport, aA as WalkMove, aB as WalkStep, aC as confidentialPending, aD as confidentialRequests, aE as footprintOf, aF as membersAddRowsSteps, aG as tableSettingsProblems, aH as whenRule } from '../types-DxVoKKpL.js';
3
+ import { b as AggregateMeasure, a as AggregateFilter, t as RecordsDataSource } from '../ports-Df3VghxK.js';
4
+ import { U as UseCase } from '../types-Ba11aOEO.js';
5
+ import { U as UseCaseProblem } from '../validate-E-g4LAZ6.js';
6
+ export { R as RESOLVABLE_FIELD_TYPE_WORDS } from '../validate-E-g4LAZ6.js';
3
7
  import '../field-CekLWOPw.js';
4
8
 
5
- declare const TABLE_KERNEL_ID = "11111111-0000-4000-8000-000000000001";
6
- type ConfidentialLevel = "viewer" | "commenter" | "editor";
7
- interface TemplateConfidentialReader {
8
- /** A member / person field of the table whose value names the reader. */
9
- field: string;
10
- level: ConfidentialLevel;
11
- /** The row's own condition, flat saved-view filter: { "cycle_manager_status": "Submitted" }. */
12
- when?: Record<string, string | number | boolean>;
13
- }
14
- interface TemplateConfidential {
15
- table: string;
16
- readers: TemplateConfidentialReader[];
17
- /** true: the person who installs it is only a reader (the organization owns the table). */
18
- makerIsReader: boolean;
19
- /** One sentence for the chair and for Arman: why this table is Confidential. */
20
- why: string;
21
- }
22
- interface TemplateTableSettings {
23
- confidential?: TemplateConfidential[];
24
- membersAddRows?: string[];
25
- }
26
- /** One request the chair runs after install (the SQL is the exact call; words are the chair's). */
27
- interface ConfidentialRequest {
28
- table: string;
29
- tableId: string;
30
- readers: Array<{
31
- field: string;
32
- level: ConfidentialLevel;
33
- when?: Record<string, unknown>;
34
- }>;
35
- makerIsReader: boolean;
36
- why: string;
37
- /** `select custom.set_table_confidential_arman_explicitly_approved(…)` with `:'arman_words'` left for the chair. */
38
- sql: string;
39
- }
40
- /** What a spec's confidential / membersAddRows say is wrong, in plain sentences ([] = fine). */
41
- declare function tableSettingsProblems(spec: TemplateSpec & TemplateTableSettings): string[];
42
- /** The plan steps that set members_add_rows (custom.record_change_many on the Table kernel, as the person). */
43
- declare function membersAddRowsSteps(spec: TemplateTableSettings, tableRef: (token: string) => string): {
44
- label: string;
45
- door: "record_change_many";
46
- args: {
47
- p_organization_id: string;
48
- p_table_id: string;
49
- p_changes: {
50
- op: string;
51
- record_id: string;
52
- patch: {
53
- members_add_rows: boolean;
54
- };
55
- }[];
56
- };
57
- }[];
58
- /** The chair's requests for one install: table ids from the install answer's `made`. */
59
- declare function confidentialRequests(spec: TemplateTableSettings, made: Array<{
60
- kind: string;
61
- ref: string;
62
- id: string | null;
63
- }>): ConfidentialRequest[];
64
- /**
65
- * A reader's `when`, as the store asks it. The flat saved-view map compiles against the row's STORED
66
- * document only (custom.record_filter_sql reads r.data), so a lookup — "both sides are submitted",
67
- * read through the review cycle — would never be true there. A Rule expression is evaluated over
68
- * custom.record_values_of(r), which works lookups and roll-ups out on read; so every condition is
69
- * written as a Rule over the installed fields' ids (REC-17: a Rule points at a Field by id).
70
- */
71
- declare function whenRule(table: string, when: Record<string, unknown>, made: Array<{
72
- kind: string;
73
- ref: string;
74
- id: string | null;
75
- }>): Record<string, unknown>;
76
- /** True while any of the template's Confidential tables is not Confidential yet (hold its forms). */
77
- declare function confidentialPending(spec: TemplateTableSettings, levels: Record<string, string | null | undefined>): boolean;
78
-
79
- /** The schema version of this file format. Bumped only when the SHAPE changes. */
80
- declare const TEMPLATE_SPEC_VERSION: 1;
81
- /**
82
- * THE RELATIVE-DATE GRAMMAR. A seed date is written relative to the day the template is
83
- * installed, so a calendar installed in March shows this week's work, not last year's:
84
- *
85
- * ANCHOR @today the install day
86
- * @mon … @sun that weekday of the install week (weeks start Monday)
87
- * @last-mon … @next-sun that weekday of the week before / after
88
- * OFFSET +3d -2w +1m -1y days / weeks / months / years (N ≤ 9999)
89
- * +2b -5b BUSINESS days (Monday–Friday): never lands on a weekend
90
- * SNAP ~b if the result is a Saturday or Sunday, move to Monday
91
- * TIME " 09:30" a moment that day, 24-hour local time in the business's
92
- * zone, written out with its offset
93
- *
94
- * "@today-3b 08:30" "@today~b 10:00" "@next-tue" "@mon+1d 14:00"
95
- *
96
- * Closed: anything else in a date field is an absolute date, which only a field flagged
97
- * `absoluteDates` (a date of birth) may hold. `resolveRelativeDates` (./validate) turns
98
- * every token into the store's own date or moment text.
99
- *
100
- * Groups: 1 anchor, 2 sign, 3 count, 4 unit, 5 snap, 6 hour, 7 minute.
101
- */
102
- declare const RELATIVE_DATE: RegExp;
103
- /** The day the validator resolves relative dates against, so every check is deterministic. */
104
- declare const TEMPLATE_REFERENCE_DATE = "2026-10-05";
105
- /** The 20 industry groups of the catalogue (handoff §5 table). The quota per group is in CATALOGUE_QUOTAS. */
106
- declare const INDUSTRY_GROUPS: readonly ["healthcare", "legal_professional", "construction_trades", "real_estate_property", "hospitality_food", "agencies_creative", "field_home_services", "retail_ecommerce", "manufacturing_logistics", "education", "nonprofit_community", "software_it", "fitness_beauty_wellness", "media_creators", "staffing_hr_recruiting", "personal_family", "events_weddings", "automotive", "agriculture_environment", "cross_industry"];
107
- type IndustryGroup = (typeof INDUSTRY_GROUPS)[number];
108
- /** The first 1,000 rows' quota per group (sums to 1,000). G3 enforces it at 1,000 and proportionally before. */
109
- declare const CATALOGUE_QUOTAS: Readonly<Record<IndustryGroup, number>>;
110
- /** The 12 jobs a template does for a business. */
111
- declare const TEMPLATE_JOBS: readonly ["intake", "scheduling", "crm_pipeline", "work_orders", "inventory", "billing", "team_hr", "projects", "content", "compliance_quality", "customer_service", "reporting"];
112
- type TemplateJob = (typeof TEMPLATE_JOBS)[number];
113
- /** The 16 features a template can teach. Each is taught by at least 40 of the first 1,000. */
114
- declare const TEACHES_FEATURES: readonly ["relations_rollups", "dimensions", "kanban", "calendar", "timeline", "gallery", "forms", "bookings", "portals", "dashboards", "drill_down", "agents", "field_governance", "import_upsert", "checklists", "documents_esign"];
115
- type TeachesFeature = (typeof TEACHES_FEATURES)[number];
116
- /**
117
- * The five places we beat the champions (ADV-P §4). Each is shown in at least 100 of the first 1,000.
118
- *
119
- * S1 — governed columns: every column says who sees it and whether AI may read it.
120
- * S2 — agents inside the data: an agent works on the table's own records.
121
- * S3 — every front door on one table: form, booking, portal, digest, webhook all land in one table.
122
- * S4 — a column can point at anything on the platform (entity reference).
123
- * S5 — imports and edits cannot lose data: an upsert import that updates and adds, or
124
- * archive → Trash → restore, shown in the walk.
125
- */
126
- declare const STRENGTHS: readonly ["S1", "S2", "S3", "S4", "S5"];
127
- type Strength = (typeof STRENGTHS)[number];
128
- /** Who installs it: a business, or a person for their own life. */
129
- declare const TEMPLATE_AUDIENCES: readonly ["organization", "individual"];
130
- type TemplateAudience = (typeof TEMPLATE_AUDIENCES)[number];
131
- /**
132
- * THE CAPABILITY WORDS a template may `require`. Closed: a word not here is a typo, and a
133
- * word the template does not use is refused. Whether each is PROVIDED today is derived by
134
- * `capabilityStatus` (./validate) from the store's registry and the records-ui layouts, so a
135
- * word flips to provided the day its lane lands, with no edit to this list.
136
- */
137
- declare const CAPABILITY_WORDS: readonly ["view.grid", "view.kanban", "view.kanban.swimlanes", "view.calendar", "view.calendar.month", "view.timeline", "view.gallery", "field.select", "field.multi_select", "field.datetime", "field.currency", "field.percent", "field.email", "field.phone", "field.url", "field.checkbox", "field.attachment", "field.member", "field.lookup", "field.rollup", "field.formula", "field.entity_reference", "field.signature", "field.rating", "choice.colors", "seed.attachments", "form", "form.question_text", "booking", "portal", "dashboard", "dashboard.multi_table", "drill_down", "dimensions", "digest", "checklist", "document", "document.esign", "notification", "stage_rules", "row_action", "import.upsert", "archive.restore", "agent", "automation"];
138
- type CapabilityWord = (typeof CAPABILITY_WORDS)[number];
139
- /**
140
- * The platform kinds an entity_reference column may point at — custom.entity_reference_kinds(),
141
- * read on the clone 2026-10-02 (the TEMPLATES lane refreshes it the way it refreshes the agent
142
- * snapshot). A word outside it is refused: the store would refuse the column.
143
- */
144
- declare const ENTITY_REFERENCE_KINDS: readonly ["agent", "agent_shortcut", "agent_template", "ai_api", "ai_endpoint", "ai_model", "ai_provider", "ai_setting", "anon_form", "app", "assessment", "canvas_comment", "canvas_item", "canvas_score", "category", "code_file", "code_folder", "code_repository", "comparison_set", "contact_submission", "content_ir_kind", "content_ir_kind_instance", "context_item", "conversation", "crm_deal", "crm_outreach_list", "cx_agent_memory", "data_store", "fc_set", "feature_doc", "flexible_data", "folder", "game_result", "heatmap_save", "hr_asset", "hr_candidate", "hr_careers_portal", "hr_checklist_template", "hr_course", "hr_crew", "hr_deduction_code", "hr_department", "hr_earning_code", "hr_employee", "hr_holiday_calendar", "hr_interview_kit", "hr_job_title", "hr_jurisdiction", "hr_jurisdiction_rule_class", "hr_leave_policy", "hr_location", "hr_pay_group", "hr_posting", "hr_record_class", "hr_requisition", "hr_schedule", "hr_schedule_template", "hr_survey", "league_membership", "learn_doc", "mandate", "marketing_initiative", "meet_meeting", "message_template", "note", "note_folder", "organization", "page_extraction_job", "party", "pc_article", "pc_episode", "pc_show", "pc_studio_run", "processed_document", "project", "quiz_session", "research_template", "research_topic", "rulebook", "sch_task", "scope_type", "seo_topic", "shared_canvas_item", "skill", "skill_render_definition", "studio_session", "study_goal", "study_media", "study_plan", "study_plan_block", "surface", "task", "thread", "tool", "tool_bundle", "transcript", "udt_document", "user_markdown_sample", "voice", "war_room", "wbx_pattern", "web_analysis_item", "web_brand", "web_provider", "web_site", "workbook", "workflow", "workflow_template", "workflow_trigger", "working_document"];
145
- /** The colours a choice may wear — the palette `display_format.options.choices[].color` holds (design-system STYLE_COLORS). */
146
- declare const CHOICE_COLORS: readonly ["slate", "green", "amber", "red", "blue", "violet", "teal"];
147
- type ChoiceColor = (typeof CHOICE_COLORS)[number];
148
- interface SharedBlockField {
149
- key: string;
150
- label: string;
151
- parityType: UseCaseField["parityType"];
152
- sensitivity: UseCaseField["sensitivity"];
153
- contextPolicy: UseCaseField["contextPolicy"];
154
- required?: boolean;
155
- /** Labels and keys that mean this field, for the copy check (normalised, lower-case words). */
156
- sameAs: readonly string[];
157
- }
158
- interface SharedBlock {
159
- /** The table's token in every organization: one table, shared by every template that uses it. */
160
- table: string;
161
- name: string;
162
- labelSingular: string;
163
- labelPlural: string;
164
- titleField: string;
165
- describes: string;
166
- fields: readonly SharedBlockField[];
167
- /** A template table matching this many of the block's fields (by type and meaning) has copied it. */
168
- copyThreshold: number;
169
- }
170
- /**
171
- * THE SHARED BLOCKS. The scope templates carried 26 byte-identical copies of a team-member
172
- * block (312 of 846 fields). Now the block is ONE seeded table per organization; a template
173
- * lists the block in `sharedBlocks` with the rows it seeds (its own people), and points its
174
- * "assigned to" columns at the block's table with an ordinary relation field — so the
175
- * column is filled, and no template declares those fields again.
176
- */
177
- declare const SHARED_BLOCKS: {
178
- readonly team_member: {
179
- readonly table: "team_member";
180
- readonly name: "Team";
181
- readonly labelSingular: "Team member";
182
- readonly labelPlural: "Team";
183
- readonly titleField: "full_name";
184
- readonly describes: "The people on the business's own team — who is assigned, who answers, who signs.";
185
- readonly fields: readonly [{
186
- readonly key: "full_name";
187
- readonly label: "Name";
188
- readonly parityType: "text";
189
- readonly sensitivity: "internal";
190
- readonly contextPolicy: "include";
191
- readonly required: true;
192
- readonly sameAs: readonly ["name", "full name", "employee name", "staff name"];
193
- }, {
194
- readonly key: "role";
195
- readonly label: "Role";
196
- readonly parityType: "text";
197
- readonly sensitivity: "internal";
198
- readonly contextPolicy: "include";
199
- readonly sameAs: readonly ["role", "job title", "title", "position"];
200
- }, {
201
- readonly key: "work_email";
202
- readonly label: "Work email";
203
- readonly parityType: "email";
204
- readonly sensitivity: "confidential";
205
- readonly contextPolicy: "summarize";
206
- readonly sameAs: readonly ["email", "work email", "email address"];
207
- }, {
208
- readonly key: "mobile";
209
- readonly label: "Mobile";
210
- readonly parityType: "phone";
211
- readonly sensitivity: "confidential";
212
- readonly contextPolicy: "exclude";
213
- readonly sameAs: readonly ["phone", "mobile", "work phone", "cell", "phone number"];
214
- }, {
215
- readonly key: "start_date";
216
- readonly label: "Start date";
217
- readonly parityType: "datetime";
218
- readonly sensitivity: "internal";
219
- readonly contextPolicy: "include";
220
- readonly sameAs: readonly ["start date", "hire date", "started", "date hired"];
221
- }];
222
- readonly copyThreshold: 3;
223
- };
224
- };
225
- type SharedBlockId = keyof typeof SHARED_BLOCKS;
226
- declare const SHARED_BLOCK_IDS: SharedBlockId[];
227
- /** One shared block this template uses, with the rows it seeds into the block's table. */
228
- interface SharedBlockUse {
229
- block: SharedBlockId;
230
- /** Keyed by the block's field keys. Relation fields elsewhere point at these row keys. */
231
- rows: UseCaseRow[];
232
- }
233
- interface TemplateField extends UseCaseField {
234
- /** Every choice of a select/multi_select wears a colour: choice word → colour. */
235
- choiceColors?: Record<string, ChoiceColor>;
236
- /** For an `entity_reference` field (S4): the platform kinds it may point at. */
237
- allowedTypes?: string[];
238
- /** For a lookup / rollup: the relation field it reads through. */
239
- via?: string;
240
- /** Lookup: the field picked on the far side. Rollup: the field aggregated. */
241
- pick?: string;
242
- /** Rollup: the aggregate along the relation. */
243
- agg?: AggregateOperation;
244
- /**
245
- * Rollup: WHICH linked records it adds up — "sessions booked", "unpaid balance", "open requests"
246
- * per parent. The saved view's own filter grammar, written against the far table: a flat map of
247
- * far-side column keys (`{ status: "open" }`) or a Rule expression over far-side field IDs. The
248
- * store refuses an unknown column or op at install (custom.field_declare).
249
- */
250
- filter?: Record<string, unknown>;
251
- /**
252
- * For a `formula` field: the formula text custom.field_declare parses (`formula_text`, through
253
- * custom.formula_parse) — fields named by LABEL in braces, functions from
254
- * custom.formula_node_kinds(): `{Total} - {Paid}`, `DATEDIFF({Starts}, {Ends}, 'minutes') / 60`.
255
- * The store computes it on read; seeds never write it.
256
- */
257
- formula?: string;
258
- /**
259
- * ELIGIBILITY across tables, on a relation field: the record this field points at must hold a
260
- * row in `table` (linked back by `relation`) matching `where`, whose `until` date is on or after
261
- * this row's `onDate` — a shift's staff member holds an unexpired food-handler card on the
262
- * shift's day. Checked on the seed and on the walk's state after every step.
263
- */
264
- eligible?: {
265
- table: string;
266
- relation: string;
267
- where?: Record<string, string>;
268
- until: string;
269
- onDate: string;
270
- };
271
- /**
272
- * A date field whose values are history, not schedule (a date of birth, a founding
273
- * date): its seed rows hold absolute dates. Every other date field is written in the
274
- * relative grammar (RELATIVE_DATE).
275
- */
276
- absoluteDates?: boolean;
277
- /**
278
- * A schedule date for a weekday-only business: every seed value must resolve to Monday–
279
- * Friday on EVERY install weekday (write it with business-day offsets "+2b" or the "~b" snap).
280
- */
281
- businessDays?: boolean;
282
- /** The value a new record gets when nobody gives one — lets a form or an import leave a required field out. */
283
- default?: unknown;
284
- /**
285
- * A public form may ask a confidential / restricted field only when it is the asker's OWN
286
- * data (a patient's member id on her own intake). Flag it here; never for anyone else's.
287
- */
288
- askOfSubject?: boolean;
289
- /** A parent or guardian answers this on a public form for a minor (youth league, school, pediatrics). */
290
- askOfGuardian?: boolean;
291
- /**
292
- * Required with `absoluteDates`: why these dates are history ("date of birth", "the year
293
- * the firm was founded"). A field flagged absolute may never drive a calendar, a timeline,
294
- * a booking, a digest, a stage rule, the Q6 question or a walk step — those are schedule.
295
- */
296
- historicalReason?: string;
297
- }
298
- interface TemplateTable extends UseCaseTable {
299
- fields: TemplateField[];
300
- /**
301
- * Ordered date pairs that hold on every seed row: [earlier, later]. A side is a field of
302
- * this table ("sent_on") or a field reached through one of its relations ("patient.date_of_birth").
303
- * A table with two or more schedule date fields declares its order here, or says why the
304
- * dates are independent (`datesIndependent`).
305
- */
306
- before?: [string, string][];
307
- datesIndependent?: string;
308
- /**
309
- * A roster of recurring slots (weekly shifts, standing roles): rows may share a title when
310
- * they differ in a date and in who or what they are for (a relation).
311
- */
312
- schedule?: boolean;
313
- /**
314
- * Date coherence across relations, declared: on every seed row `earlier` is on or before
315
- * `later`. A side is a field of this table ("invoice_date") or one reached through a relation
316
- * ("engagement.start_date"). `onlyWhen` limits the pair to rows whose field holds one of the
317
- * values (a report is due only on an Awarded grant). A billing or grants template declares at
318
- * least one pair that crosses a relation.
319
- */
320
- datePairs?: {
321
- earlier: string;
322
- later: string;
323
- onlyWhen?: {
324
- field: string;
325
- values: string[];
326
- };
327
- }[];
328
- /**
329
- * CROSS-TABLE REALISM, stated once on the CHILD table (the one holding the relation) and
330
- * enforced on every seed row. A relation whose two sides both carry a schedule date needs a
331
- * childDates entry; both a status, a statusAgrees entry.
332
- *
333
- * childDates: this row's date is on or after its parent's ("start_on" ≥ "requisition.opened_on").
334
- */
335
- childDates?: {
336
- relation: string;
337
- field: string;
338
- parentField: string;
339
- }[];
340
- /** withinParent: this row's number stays within its parent's (deal.price ≤ client.budget_max) unless a status says otherwise. */
341
- withinParent?: {
342
- relation: string;
343
- field: string;
344
- op: "<=" | ">=";
345
- parentField: string;
346
- unless?: {
347
- field: string;
348
- values: string[];
349
- };
350
- }[];
351
- /**
352
- * statusAgrees: a child in one of `childStatus` means its parent's `parentField` is one of
353
- * `parentStatus` (deal Closed ⇒ listing Sold); `maxPerParent` caps how many children of one
354
- * parent may sit in those statuses (one accepted offer per listing).
355
- */
356
- statusAgrees?: {
357
- relation: string;
358
- field: string;
359
- childStatus: string[];
360
- parentField: string;
361
- parentStatus: string[];
362
- maxPerParent?: number;
363
- }[];
364
- /** countMatches: a stored count equals the number of linked rows. Prefer a rollup, which the store computes. */
365
- countMatches?: {
366
- field: string;
367
- childTable: string;
368
- childRelation: string;
369
- }[];
370
- /**
371
- * STATUS IMPLIES FIELDS: a row in one of `when` (on `field`) has every `filled` field filled
372
- * and every `equals` field at that value — Paid ⇒ paid_on set and balance 0; Signed ⇒ the
373
- * signature filled. Checked on every seed row and after every walk step that changes a row.
374
- */
375
- statusImplies?: {
376
- field: string;
377
- when: string[];
378
- filled?: string[];
379
- equals?: Record<string, unknown>;
380
- }[];
381
- /**
382
- * DATE-DRIVEN STATUS: `field` follows `dateField` measured from the install day, on every
383
- * install weekday — bands in days from today, `from` inclusive, `to` exclusive:
384
- * [{status: "Expired", to: 0}, {status: "Renewal due", from: 0, to: 61}, {status: "Current", from: 61}].
385
- * A row whose status is one of the bands' statuses sits in the band its date says. (A status the
386
- * store should compute is better a formula: IF(DATEDIFF(TODAY(), {Expires on}, 'days') < 0, …).)
387
- */
388
- statusByDate?: {
389
- field: string;
390
- dateField: string;
391
- bands: {
392
- status: string;
393
- from?: number;
394
- to?: number;
395
- }[];
396
- };
397
- /** Relations (by field key) whose two sides' dates and statuses truly do not constrain each other, each with the reason. */
398
- independentOf?: Record<string, string>;
399
- /**
400
- * What one row is: a person, an animal or a thing. The personal-data floors (date of birth,
401
- * allergies, diagnoses, medications, member ids) bind people only — a dog's birthday is not
402
- * personal data. Undeclared, a table holds people when it has a name and a phone or email.
403
- */
404
- subject?: "person" | "animal" | "thing";
405
- /**
406
- * Lane 10 FD. An echo of the template's `foundation` list (R13), which is the ONE source the
407
- * installers read. Optional; when present the validator requires it to agree with the list.
408
- */
409
- foundation?: boolean;
410
- }
411
- declare const TEMPLATE_VIEW_KINDS: readonly ["grid", "kanban", "calendar", "gallery", "timeline"];
412
- type TemplateViewKind = (typeof TEMPLATE_VIEW_KINDS)[number];
413
- interface TemplateViewSort {
414
- field: string;
415
- direction: "asc" | "desc";
416
- }
417
- interface TemplateViewBase {
418
- /** snake_case, unique within the template. */
419
- token: string;
420
- /** What a person clicks: "Today's chairs", "Intake board". */
421
- name: string;
422
- /** The table token it looks at. */
423
- table: string;
424
- /** The view the table opens on (at most one per table). */
425
- isDefault?: boolean;
426
- /** custom.view_declare `filters`: Field key → value (scalar equality, null = unset, object = window). */
427
- filters?: Record<string, AggregateFilter>;
428
- /**
429
- * Any-of conditions: Field key → the values a row may hold ("Open requests" = New, In progress,
430
- * Waiting). The store's flat `filters` map is equality only; this is declared as the view's
431
- * `where` Rule expression (S2-PRIME) — `{op: "and", args: [{op: "or", args: [{op: "eq", args:
432
- * [{field: <field id>}, {const: <value>}]}, …]}, …]}`, Fields by id — which custom.record_filter_sql
433
- * compiles for the grid and the board. Digests and the notifier read only `filters`, never this.
434
- */
435
- anyOf?: Record<string, string[]>;
436
- sorts?: TemplateViewSort[];
437
- /** Field keys hidden on this view (presentation.hiddenFields). */
438
- hiddenFields?: string[];
439
- }
440
- interface TemplateGridView extends TemplateViewBase {
441
- kind: "grid";
442
- groupBy?: string;
443
- }
444
- interface TemplateKanbanView extends TemplateViewBase {
445
- kind: "kanban";
446
- /** `group_field`: the choice field whose values are the columns. */
447
- groupBy: string;
448
- /** `swimlane_field`: never the column field itself. */
449
- swimlaneBy?: string;
450
- /** `measure`: a number field totalled under each column heading. */
451
- measure?: string;
452
- }
453
- interface TemplateCalendarView extends TemplateViewBase {
454
- kind: "calendar";
455
- /** `date_field`: a datetime, so every card has a time on the day. */
456
- dateField: string;
457
- /** The records are whole-day by intent (a deadline, a due date). */
458
- allDay?: boolean;
459
- /** "month" needs `view.calendar.month` (lane 10). */
460
- span?: "month" | "week";
461
- }
462
- interface TemplateGalleryView extends TemplateViewBase {
463
- kind: "gallery";
464
- /** `image_field`: the file field shown as each card's picture. Needs `seed.attachments`. */
465
- coverField: string;
466
- }
467
- interface TemplateTimelineView extends TemplateViewBase {
468
- kind: "timeline";
469
- startField: string;
470
- endField: string;
471
- groupBy?: string;
472
- }
473
- type TemplateView = TemplateGridView | TemplateKanbanView | TemplateCalendarView | TemplateGalleryView | TemplateTimelineView;
474
- interface TemplateFormField extends UseCaseFormField {
475
- /**
476
- * The question as it is ASKED: "What brings you in today?" — not the column label.
477
- * Sent as the question's `ask` to custom.form_declare / booking_declare (`help` rides beside it).
478
- */
479
- ask: string;
480
- }
481
- interface TemplateForm extends UseCaseForm {
482
- fields: TemplateFormField[];
483
- }
484
- interface TemplateDimensionOverride {
485
- /** An inferred dimension key (custom._table_dimensions_infer): a single choice, a single relation, a tick box, a date, created_at or updated_at. */
486
- key: string;
487
- label?: string;
488
- hidden?: boolean;
489
- }
490
- interface TemplateMeasureOverride {
491
- /** An inferred measure key (count, sum_x, avg_x, min_x, max_x, filled_x) — rename/hide only — or a NEW key. */
492
- key: string;
493
- label?: string;
494
- hidden?: boolean;
495
- /** A NEW measure only: one of custom.agg_operations() except count. */
496
- op?: Exclude<AggregateOperation, "count">;
497
- /** A NEW measure only: the column it reads. */
498
- of?: string;
499
- }
500
- interface TemplateDrillPath {
501
- key: string;
502
- /** Dimension keys, coarsest first; a date takes ":year" | ":quarter" | ":month" | ":week" | ":day". */
503
- levels: string[];
504
- }
505
- interface TemplateDimensions {
506
- table: string;
507
- dimensions?: TemplateDimensionOverride[];
508
- measures?: TemplateMeasureOverride[];
509
- paths?: TemplateDrillPath[];
510
- default?: {
511
- by?: string[];
512
- show?: string[];
513
- };
514
- }
515
- interface TemplateBookingWindow {
516
- /** 0 = Sunday … 6 = Saturday. */
517
- weekday: number;
518
- /** "09:00". */
519
- from: string;
520
- /** "17:00", later than `from`. */
521
- to: string;
522
- }
523
- interface TemplateBooking {
524
- kind: "booking";
525
- token: string;
526
- title: string;
527
- table: string;
528
- questions: TemplateFormField[];
529
- availability: {
530
- timezone?: string;
531
- slotMinutes: number;
532
- bufferMinutes?: number;
533
- leadMinutes?: number;
534
- maxPerDay?: number;
535
- days?: number;
536
- windows: TemplateBookingWindow[];
537
- };
538
- slug?: string;
539
- /**
540
- * The statuses of rows that came through (or wait on) this booking page. Only those rows must
541
- * sit in its windows; rows that reached later stages by other routes (a same-day emergency
542
- * dispatch) do not. Default: Booked, Confirmed, Requested, Held, Pending, Scheduled, Cancelled.
543
- */
544
- bookedStages?: string[];
545
- }
546
- interface TemplatePortalTable {
547
- table: string;
548
- /** The relation field of `table` that points at the portal's client table — "only theirs". */
549
- namesVia: string;
550
- /** Never empty; never a restricted / confidential field or one the AI is kept from. */
551
- visibleFields: string[];
552
- editableFields?: string[];
553
- comments?: boolean;
554
- }
555
- interface TemplatePortal {
556
- kind: "portal";
557
- token: string;
558
- title: string;
559
- /** The table whose records are the portal's clients (patients, owners, tenants). */
560
- clientTable: string;
561
- tables: TemplatePortalTable[];
562
- /** Form tokens offered inside the portal. */
563
- forms?: string[];
564
- slug?: string;
565
- }
566
- interface TemplateDashboardBlock {
567
- title: string;
568
- kind: DashboardBlockKind;
569
- /** Absent = the dashboard's own table. */
570
- table?: string;
571
- groupBy?: string[];
572
- measures?: AggregateMeasure[];
573
- bucket?: {
574
- key: string;
575
- by: AggregateBucket;
576
- };
577
- filter?: Record<string, AggregateFilter>;
578
- span?: number;
579
- /** `stuck` only. */
580
- stateKey?: string;
581
- days?: number;
582
- }
583
- interface TemplateDashboard {
584
- kind: "dashboard";
585
- token: string;
586
- name: string;
587
- table: string;
588
- /** At least two charts: bar, column, line or donut (`number`, `table` and `stuck` are not charts). */
589
- blocks: TemplateDashboardBlock[];
590
- }
591
- interface TemplateDrillDown {
592
- kind: "drill_down";
593
- token: string;
594
- name: string;
595
- table: string;
596
- /** A `paths[].key` of this table's `dimensions` entry. */
597
- path: string;
598
- }
599
- interface TemplateDigest {
600
- kind: "digest";
601
- token: string;
602
- name: string;
603
- /** The view token whose records the digest sends. */
604
- view: string;
605
- cadence: SubscriptionCadence;
606
- /** "monday 08:00". */
607
- schedule?: string;
608
- channel?: "in_app" | "email" | "sms";
609
- }
610
- interface TemplateChecklistStep {
611
- ref: string;
612
- title: string;
613
- role?: string;
614
- dueDays?: number;
615
- dependsOn?: string[];
616
- requires?: {
617
- kind: "none" | "note";
618
- } | {
619
- kind: "answer";
620
- key: string;
621
- label: string;
622
- } | {
623
- kind: "record_field";
624
- key: string;
625
- label?: string;
626
- } | {
627
- kind: "form";
628
- form: string;
629
- } | {
630
- kind: "document";
631
- document: string;
632
- };
633
- }
634
- interface TemplateChecklist {
635
- kind: "checklist";
636
- token: string;
637
- name: string;
638
- aboutTable: string;
639
- roles?: {
640
- role: string;
641
- label?: string;
642
- }[];
643
- trigger?: {
644
- kind: "manual";
645
- } | {
646
- kind: "record_created";
647
- table: string;
648
- } | {
649
- kind: "status_reached";
650
- table: string;
651
- status: string;
652
- };
653
- steps: TemplateChecklistStep[];
654
- }
655
- interface TemplateDocument {
656
- kind: "document";
657
- token: string;
658
- name: string;
659
- describes: string;
660
- table: string;
661
- /** The subject or title line; merge fields allowed. */
662
- title: string;
663
- /**
664
- * Prose with {{field_key}} merge fields, each a field of `table` (the installer writes
665
- * {{field:<id>}}, the only token custom.doc_render_body resolves). No {{today}}, no
666
- * {{business.x}}, no signature field (a signature never merges into the body).
667
- */
668
- body: string;
669
- /** Sent for e-signature (needs `document.esign`). */
670
- signature?: boolean;
671
- }
672
- interface TemplateNotification {
673
- kind: "notification";
674
- token: string;
675
- name: string;
676
- describes: string;
677
- when: UseCaseNotificationTrigger;
678
- /** Who it goes to, in the business's own words: "the assigned hygienist". */
679
- audience: string;
680
- channel: NotificationChannel;
681
- /** The message; {{field_key}} merge fields of the watched table only. */
682
- message: string;
683
- }
684
- interface TemplateStageRules {
685
- kind: "stage_rules";
686
- token: string;
687
- /** "Route board" — the lifecycle's own name. */
688
- name: string;
689
- table: string;
690
- /** The choice field holding the stage. */
691
- stageField: string;
692
- /** Stage → what is true of a record sitting there, in the staff's words (every stage). */
693
- stages: Record<string, string>;
694
- transitions?: {
695
- from: string;
696
- to: string;
697
- }[];
698
- /** Stage → field keys that must be filled to land there. */
699
- requires?: Record<string, string[]>;
700
- /** Stage → how many cards may sit there at once. */
701
- limits?: Record<string, number>;
702
- movesMessage?: string;
703
- /**
704
- * Status ↔ date coherence, enforced on every seed row for every install weekday: the date
705
- * field, and per stage whether its date is in the past (on or before install day), today,
706
- * or the future (on or after install day). A stage left out is unconstrained.
707
- */
708
- dateField?: string;
709
- /** Every stage is listed once a dateField is declared; "any" says a stage's date is unconstrained, on purpose. */
710
- /** "none": this stage has no date yet ("New call", "Draft") — its date field is EMPTY. */
711
- stageDates?: Record<string, "past" | "today" | "future" | "any" | "none">;
712
- /** Why a time-bound stage ("No-show", "Completed", "Scheduled"…) is "any": one real sentence (≥ 6 words) per such stage. */
713
- anyBecause?: Record<string, string>;
714
- /**
715
- * Moves OUT of a terminal stage (Cancelled, No-show, Lost, Declined, Closed, Withdrawn…) are
716
- * refused unless declared here with the business reason — a reopened deal, a rebooked guest.
717
- */
718
- reopen?: {
719
- from: string;
720
- to: string;
721
- because: string;
722
- }[];
723
- /**
724
- * A stage that needs a linked child: "First pickup booked" ⇒ at least `min` (default 1) row of
725
- * `table` whose `relation` points at this row and whose `field` is one of `in`. Checked on the
726
- * seed and on the walk's state after every step.
727
- */
728
- requiresChild?: Record<string, {
729
- table: string;
730
- relation: string;
731
- field?: string;
732
- in?: string[];
733
- min?: number;
734
- }>;
735
- }
736
- interface TemplateRowAction {
737
- kind: "row_action";
738
- token: string;
739
- table: string;
740
- name: string;
741
- actionKind: "update" | "agent";
742
- confirm?: boolean;
743
- color?: ChoiceColor;
744
- /** `update`: what it writes. Fields by key; the installer resolves ids. */
745
- steps?: ({
746
- field: string;
747
- set: "value";
748
- value: unknown;
749
- } | {
750
- field: string;
751
- set: "clear";
752
- })[];
753
- /** `agent`: what the record chat opens with. */
754
- prompt?: string;
755
- }
756
- interface TemplateAutomation {
757
- kind: "automation";
758
- token: string;
759
- name: string;
760
- when: UseCaseNotificationTrigger;
761
- /** What happens, in the business's words: "text the owner the pickup window". */
762
- then: string;
763
- }
764
- type TemplateExtra = TemplateBooking | TemplatePortal | TemplateDashboard | TemplateDrillDown | TemplateDigest | TemplateChecklist | TemplateDocument | TemplateNotification | TemplateStageRules | TemplateRowAction | TemplateAutomation;
765
- type TemplateExtraKind = TemplateExtra["kind"];
766
- declare const TEMPLATE_EXTRA_KINDS: readonly TemplateExtraKind[];
767
- interface TemplateAgentVariable {
768
- /** One of the platform agent's own variable names (templates/AGENTS.snapshot.json). */
769
- name: string;
770
- /** The table token bound to it at install. */
771
- table: string;
772
- describes: string;
773
- /**
774
- * Optional (Kits → Template merge): the full merge-field binding instead of the whole-table
775
- * default. Its `table` must equal `table` above.
776
- */
777
- binding?: TemplateMergeBinding;
778
- }
779
- /**
780
- * Q6: one question, and the exact `custom.record_aggregate` answer it must give. The
781
- * validator recomputes the answer from the seed rows with the store's own semantics
782
- * (text-equality filters, half-open date windows, sum over nothing is null, no rounding).
783
- */
784
- interface TemplateAgentQuestion {
785
- ask: string;
786
- /** Why the owner asks it — what they do differently depending on the answer. */
787
- whyItMatters: string;
788
- expect: {
789
- table: string;
790
- measure: AggregateMeasure;
791
- /**
792
- * Scalar equality, null = unset, or a {from, to} window on a date field whose bounds are
793
- * relative tokens WITH a time ("@today-7d 00:00"), never a bare or absolute date. The
794
- * filter may not match 90% or more of the table's rows (that is "how many are there").
795
- */
796
- filter?: Record<string, AggregateFilter>;
797
- /** Never 0 and never null. */
798
- answer: number;
799
- unit: string;
800
- };
801
- }
802
- /** The platform agent every template copies unless it says why not (`agentReason`). */
803
- declare const DEFAULT_TEMPLATE_AGENT: {
804
- readonly id: "4cd676c6-f55d-4426-b7eb-a9d0273566ec";
805
- readonly name: "Answers From Your Tables";
806
- };
807
- interface TemplateAgent {
808
- /** The platform agent copied — id AND name, as the committed catalogue snapshot has them. */
809
- platformAgent: {
810
- id: string;
811
- name: string;
812
- };
813
- /** Required when platformAgent is not DEFAULT_TEMPLATE_AGENT: why this template needs another agent. */
814
- agentReason?: string;
815
- /** The copy's name in the installed org. */
816
- name: string;
817
- variables: TemplateAgentVariable[];
818
- question: TemplateAgentQuestion;
819
- /** Optional (Kits → Template merge): what "Try it" sends the copy. */
820
- tryIt?: TemplateTryIt;
821
- }
822
- /**
823
- * The merge-field binding, with the two ids replaced by template-local handles the host resolves
824
- * at install: `table` (a table token) and `rowIndex` (the index of a seed row of that table).
825
- * `collection` = the table's rows (one text, via `transform`); `reference` = one row (`rowIndex`);
826
- * `value` = one field (`field`) of one row (`rowIndex`).
827
- */
828
- interface TemplateMergeBinding {
829
- semantic: "collection" | "reference" | "value";
830
- table: string;
831
- rowIndex?: number;
832
- field?: string;
833
- transform?: {
834
- name: "list";
835
- template?: string;
836
- join?: string;
837
- max?: number;
838
- header?: string;
839
- };
840
- limit?: number;
841
- sort?: {
842
- field: string;
843
- dir: "asc" | "desc";
844
- };
845
- match?: Record<string, unknown>;
846
- /** What the agent sees when nothing matches (default "absent"). */
847
- missing?: string;
848
- }
849
- /** What "Try it" sends a template's agent copy: the user's message and/or its other variables. */
850
- interface TemplateTryIt {
851
- userInput?: string;
852
- variables?: Record<string, string>;
853
- }
854
- interface TemplateExtraAgentVariable {
855
- /** One of the platform agent's own variable names (templates/AGENTS.snapshot.json). */
856
- name: string;
857
- describes: string;
858
- binding: TemplateMergeBinding;
859
- }
860
- /** One more agent a template copies (no Q6: its question is the primary agent's). */
861
- interface TemplateExtraAgent {
862
- /** Template-local handle: guide highlights and workflow `{{agent:key}}` placeholders use it. */
863
- key: string;
864
- platformAgent: {
865
- id: string;
866
- name: string;
867
- };
868
- /** Why this template carries this agent — a full sentence (agents never author agents). */
869
- agentReason: string;
870
- name: string;
871
- variables: TemplateExtraAgentVariable[];
872
- tryIt?: TemplateTryIt;
873
- }
874
- /** A workflow made at install through aidream `POST /workflows`; `{{table:<token>}}` / `{{agent:<key>}}` are resolved. */
875
- interface TemplateWorkflow {
876
- key: string;
877
- name: string;
878
- description: string;
879
- definition: unknown;
880
- }
881
- /** One display step of how the template works (NOT the gated `walk`). */
882
- interface TemplateGuideStep {
883
- title: string;
884
- body: string;
885
- /** `agent` key "agent" names the primary agent. */
886
- highlight?: {
887
- kind: "table" | "agent" | "workflow" | "binding";
888
- key: string;
889
- };
890
- }
891
- /** One CSV-shaped import: a header of field keys and the rows under it, as the file holds them. */
892
- interface WalkImport {
893
- kind: "import";
894
- table: string;
895
- /** What the file is called: "October customer list.csv". */
896
- sourceName: string;
897
- /** The field that makes a row the same row (`p_dedupe_key`); it carries a `unique` rule. */
898
- dedupeKey: string;
899
- /** The header row: field keys (the mapping is identity). */
900
- columns: string[];
901
- /** The data rows, cell by cell, as text — at least one updates a seed row and one is new. */
902
- rows: string[][];
903
- }
904
- /** One row's move inside a grouped `moves` step. */
905
- interface WalkMove {
906
- table: string;
907
- row: string;
908
- field: string;
909
- to: string;
910
- set?: Record<string, unknown>;
911
- }
912
- type WalkAction = {
913
- kind: "open";
914
- surface: string;
915
- }
916
- /**
917
- * A stage move, optionally landing with the fields that stage requires or implies (`set`:
918
- * "mark Paid" writes paid_on and balance in the same step). Judged as ONE step: stage
919
- * requires, statusImplies, date pairs and the stage's date rule are checked on the result.
920
- * A checker or installer runs it as ONE store call, as the person:
921
- * `pipeline_move(p_record_id, p_to, p_also => set)` — the door writes `p_also` with the
922
- * stage in the same record write, judged by the same Rules (the board's "this move needs
923
- * these fields" prompt makes the same call). Never record_update first: that leaves a
924
- * half-moved row if the move is then refused.
925
- */
926
- | {
927
- kind: "move";
928
- table: string;
929
- row: string;
930
- field: string;
931
- to: string;
932
- set?: Record<string, unknown>;
933
- }
934
- /**
935
- * A GROUPED step: 2–3 linked moves made together ("accept the quote AND move its lead to
936
- * Agreement signed"). Each move is judged against its own table's transitions, requires,
937
- * statusImplies and date rules; the template's cross-table rules (statusAgrees,
938
- * withinParent, childDates) are judged on the state after the WHOLE group. A checker runs it
939
- * as one `pipeline_move(p_record_id, p_to, p_also => set)` per row, in the listed order, as
940
- * the person; the expect asserts where one of the moved rows landed.
941
- */
942
- | {
943
- kind: "moves";
944
- moves: WalkMove[];
945
- }
946
- /**
947
- * One field (`field` + `value`) or several at once (`set: {field: value, …}` — "mark paid"
948
- * sets status, paid and balance together); the coherence rules judge the whole result.
949
- */
950
- | {
951
- kind: "edit";
952
- table: string;
953
- row: string;
954
- field?: string;
955
- value?: unknown;
956
- set?: Record<string, unknown>;
957
- } | {
958
- kind: "submit_form";
959
- form: string;
960
- values: Record<string, unknown>;
961
- } | {
962
- kind: "archive";
963
- table: string;
964
- row: string;
965
- } | {
966
- kind: "restore";
967
- table: string;
968
- row: string;
969
- } | WalkImport | {
970
- kind: "ask_agent";
971
- };
972
- type WalkAssertion =
973
- /** The surface renders with at least `minItems` (≥ 1) records. */
974
- /**
975
- * The surface renders with at least `minItems` (≥ 1) records. `within` is the date window the
976
- * step talks about ("the next three weeks"): relative tokens on the view's date field, checked
977
- * on every install weekday. A step that names a span on a calendar or timeline must carry it.
978
- */
979
- {
980
- kind: "renders";
981
- surface: string;
982
- minItems: number;
983
- within?: {
984
- from?: string;
985
- to?: string;
986
- };
987
- }
988
- /** Over the walk's state after this step; never 0. */
989
- | {
990
- kind: "count";
991
- table: string;
992
- where?: Record<string, AggregateFilter>;
993
- equals: number;
994
- } | {
995
- kind: "value";
996
- table: string;
997
- row: string;
998
- field: string;
999
- equals: unknown;
1000
- } | {
1001
- kind: "aggregate";
1002
- table: string;
1003
- measure: AggregateMeasure;
1004
- where?: Record<string, AggregateFilter>;
1005
- equals: number;
1006
- }
1007
- /** After `ask_agent`: the exact number the agent must answer (= agent.question.expect.answer). */
1008
- | {
1009
- kind: "agent_answer";
1010
- equals: number;
1011
- }
1012
- /** After `archive` / `restore`: the row it acted on is (or is no longer) archived. */
1013
- | {
1014
- kind: "archived";
1015
- table: string;
1016
- row: string;
1017
- equals: boolean;
1018
- };
1019
- interface WalkStep {
1020
- /** What the person does, in plain words: "Drag Rosa to Scheduled". */
1021
- says: string;
1022
- action: WalkAction;
1023
- expect: WalkAssertion;
1024
- }
1025
- /** A table marked as day-one foundation data (R13): kept for the reason given. */
1026
- interface TemplateFoundation {
1027
- table: string;
1028
- keptFor: string;
1029
- }
1030
- interface TemplateSource {
1031
- title: string;
1032
- url?: string;
1033
- /** What was taken: structure ideas only — never text, data or a real person. */
1034
- took: string;
1035
- }
1036
- interface TemplateProvenance extends UseCaseProvenance {
1037
- sources: TemplateSource[];
1038
- /** Every domain an email, website or url in the file uses. Each must not resolve in DNS (G6). */
1039
- fictionalDomains: string[];
1040
- /** Every street a numbered address in the file is on: invented, never a real street. */
1041
- fictionalStreets: string[];
1042
- }
1043
- /** The five singular artefacts a UseCase carries; a template derives them (toUseCase). */
1044
- type UseCaseSingulars = "form" | "pipeline" | "dashboardQuestion" | "documentTemplate" | "notificationRule";
1045
- /**
1046
- * ONE TEMPLATE: the UseCase's business, tables and relationships, with the singulars
1047
- * replaced by their plural, installable forms (forms[], stage_rules / document /
1048
- * notification extras, the agent's question).
1049
- */
1050
- interface TemplateSpec extends Omit<UseCase, UseCaseSingulars | "tables" | "provenance" | "industry"> {
1051
- /** The schema version of this file (TEMPLATE_SPEC_VERSION). */
1052
- specVersion: typeof TEMPLATE_SPEC_VERSION;
1053
- /** The CATALOGUE.json row this realises: "T0042". Stable, never positional. */
1054
- catalogueId: string;
1055
- industry: IndustryGroup;
1056
- /** The practitioner's own vertical: "Dental practice", "Residential HVAC". */
1057
- vertical: string;
1058
- job: TemplateJob;
1059
- audience: TemplateAudience;
1060
- teaches: TeachesFeature;
1061
- strengths: Strength[];
1062
- requires: CapabilityWord[];
1063
- tables: TemplateTable[];
1064
- sharedBlocks: SharedBlockUse[];
1065
- views: TemplateView[];
1066
- forms: TemplateForm[];
1067
- dimensions: TemplateDimensions[];
1068
- extras: TemplateExtra[];
1069
- agent: TemplateAgent;
1070
- /** Three teaching steps, plus an optional fourth that is the ask_agent step. */
1071
- walk: [WalkStep, WalkStep, WalkStep] | [WalkStep, WalkStep, WalkStep, WalkStep];
1072
- foundation: TemplateFoundation[];
1073
- provenance: TemplateProvenance;
1074
- /** The gallery card's picture (lane 2), relative to the template file. */
1075
- previewImage?: string;
1076
- /** Content version: an integer, bumped on every published change. */
1077
- version: number;
1078
- /**
1079
- * Lane 12 P7: tables that are Confidential (asked of the chair after install — a template never
1080
- * sets the level itself) and tables whose members add their own rows. See ./confidential.
1081
- */
1082
- confidential?: TemplateConfidential[];
1083
- membersAddRows?: string[];
1084
- /** Kits → Template merge: more agents the install copies, after `agent`. */
1085
- extraAgents?: TemplateExtraAgent[];
1086
- /** Kits → Template merge: workflows the install creates. */
1087
- workflows?: TemplateWorkflow[];
1088
- /** Kits → Template merge: how-it-works steps, shown only (the gated teaching steps are `walk`). */
1089
- guide?: TemplateGuideStep[];
1090
- }
1091
- /** "3 tables · 2 views · 1 form · 1 booking" plus the counts it is made of — what uninstall takes back. */
1092
- interface TemplateFootprint {
1093
- tables: number;
1094
- /** Shared-block tables it seeds rows into (not owned: uninstall archives its rows only). */
1095
- sharedBlocks: number;
1096
- views: number;
1097
- forms: number;
1098
- dimensions: number;
1099
- extras: Partial<Record<TemplateExtraKind, number>>;
1100
- agents: number;
1101
- /** Workflows an install creates (host step). */
1102
- workflows: number;
1103
- /**
1104
- * custom.portal_declare opens the organization's outside sign-in. Q7: uninstall restores
1105
- * the setting it found (the installer records the before-value).
1106
- */
1107
- opensOutsideSignIn: boolean;
1108
- line: string;
1109
- }
1110
- /** The footprint, DERIVED from the spec — never written by hand, so it cannot drift. */
1111
- declare function footprintOf(spec: Pick<TemplateSpec, "tables" | "views" | "forms" | "extras" | "agent" | "dimensions" | "sharedBlocks"> & Partial<Pick<TemplateSpec, "extraAgents" | "workflows">>): TemplateFootprint;
1112
- declare const CATALOGUE_STATUSES: readonly ["planned", "authoring", "checking", "waiting_on_lane_10", "ready", "published", "retired"];
1113
- type CatalogueStatus = (typeof CATALOGUE_STATUSES)[number];
1114
- interface CatalogueRow {
1115
- /** Stable forever: a retired row keeps its id with status "retired"; ids are never reused. */
1116
- catalogueId: string;
1117
- industry: IndustryGroup;
1118
- /** The vertical within the group: "Dental practice". */
1119
- vertical: string;
1120
- job: TemplateJob;
1121
- teaches: TeachesFeature;
1122
- strengths: Strength[];
1123
- audience: TemplateAudience;
1124
- /** One sentence the writer starts from: who, what business, what job. */
1125
- personaSeed: string;
1126
- ownerLane: string;
1127
- status: CatalogueStatus;
1128
- /** "scope-template:<key>" | "use-case:<id>" | "new". */
1129
- source: string;
1130
- /** Why a retired row was retired ("duplicate of T0009"). */
1131
- retiredBecause?: string;
1132
- /** The gallery card's picture, once the template has one. */
1133
- previewImage?: string;
1134
- /** Capabilities this row will need that may still be held (seed.attachments, automation), so batches can skip held rows. */
1135
- requires?: CapabilityWord[];
1136
- /**
1137
- * The real install check of the CURRENT file (scripts/templates-publish.ts verify): installed through
1138
- * the template family on the clone as a person, then uninstalled. `fileHash` pins which file passed.
1139
- */
1140
- installCheck?: {
1141
- result: "pass" | "fail";
1142
- /** Where the install ran: "live" since 2026-10-04 (Arman 2026-10-03: checks run on live; the clone is for destructive rehearsals only). */
1143
- target: "clone" | "live";
1144
- checkedAt: string;
1145
- fileHash: string;
1146
- wallMs: number;
1147
- installMs?: number;
1148
- steps?: number;
1149
- calls?: number;
1150
- orgId?: string;
1151
- /** The refusal verbatim (store sentence, validator problem, or uninstall leftover). */
1152
- refusal?: string;
1153
- };
1154
- /** Set by scripts/templates-publish.ts publish once declared for everyone on production. */
1155
- published?: {
1156
- templateId: string;
1157
- version: number;
1158
- steps: number;
1159
- publishedAt: string;
1160
- fileHash: string;
1161
- };
1162
- }
1163
- /** One platform agent a template may copy (templates/AGENTS.snapshot.json). */
1164
- interface AgentSnapshotRow {
1165
- id: string;
1166
- name: string;
1167
- variables: string[];
1168
- }
1169
- /** One entry of templates/RETIRED_IDS.json — append-only. */
1170
- interface RetiredId {
1171
- catalogueId: string;
1172
- retiredOn: string;
1173
- because: string;
1174
- }
1175
-
1176
9
  /** The UTC offset ("-04:00") of a local wall-clock moment in an IANA zone. */
1177
10
  declare function zoneOffset(localIso: string, timeZone: string): string;
1178
11
  /** One token → "2026-10-08" or "2026-10-08T09:30:00-04:00". `null` when it is not a token. */
@@ -1641,8 +474,17 @@ interface TemplateInstallPlan {
1641
474
  /** The business's IANA zone: install-relative dates resolve in it. */
1642
475
  timezone: string;
1643
476
  steps: TemplatePlanStep[];
1644
- /** The host's step (the kit path's agent copy), answered by custom.template_install once installed. */
1645
- agent: TemplatePlanAgent;
477
+ /**
478
+ * The host's step (the kit path's agent copy), answered by custom.template_install once installed.
479
+ * Absent for a spec with no agent (a describe one-off): the door answers no agent step.
480
+ */
481
+ agent?: TemplatePlanAgent;
482
+ /**
483
+ * Ids known before the first step (`ref:tables.<token>` → an existing table's id, for each table that
484
+ * `bindsTo` one): custom.template_install starts its id map with these, so every later step and every
485
+ * `made` entry resolves the bound table exactly as if the install had made it.
486
+ */
487
+ ids?: Record<string, string>;
1646
488
  /** Kits → Template merge (optional): more agent copies, then workflows — host steps too (./extras). */
1647
489
  extraAgents?: TemplateHostExtras["extraAgents"];
1648
490
  workflows?: TemplateHostExtras["workflows"];
@@ -1749,4 +591,4 @@ declare function runTemplateDoor(source: RecordsDataSource, door: TemplateFamily
1749
591
  /** Tables a plan makes (for a suite): the `tables.*` refs its steps save. */
1750
592
  declare function planTables(plan: TemplateInstallPlan): string[];
1751
593
 
1752
- export { type AgentSnapshotRow, type AggregateOutcome, CAPABILITY_WORDS, CATALOGUE_QUOTAS, CATALOGUE_STATUSES, CHOICE_COLORS, type CapabilityStatus, type CapabilityWord, type CatalogueRow, type CatalogueStatus, type ChoiceColor, type ConfidentialLevel, type ConfidentialRequest, DEFAULT_TEMPLATE_AGENT, DESIGNATED_REAL_NUMBERS, type DerivedUseCase, ENTITY_REFERENCE_KINDS, FORMULA_FUNCTIONS, INDUSTRY_GROUPS, INSTALL_PLAN_VERSION, type IndustryGroup, MAIN_TABLE_ROWS_MAX, MAIN_TABLE_ROWS_MIN, PUBLIC_MAIL_DOMAINS, RECORDS_UI_CALENDAR_MODES, RECORDS_UI_FIELD_SURFACES, RECORDS_UI_VIEW_LAYOUTS, RELATIVE_DATE, type RetiredId, SERVER_DATE_GRAMMAR, SHARED_BLOCKS, SHARED_BLOCK_IDS, STRENGTHS, type SeedRow, type SharedBlock, type SharedBlockField, type SharedBlockId, type SharedBlockUse, type Strength, TABLES_MAX, TABLES_MIN, TABLE_KERNEL_ID, TEACHES_FEATURES, TEMPLATE_AUDIENCES, TEMPLATE_EXTRA_KINDS, TEMPLATE_JOBS, TEMPLATE_PLAN_DOORS, TEMPLATE_REFERENCE_DATE, TEMPLATE_SPEC_VERSION, TEMPLATE_VIEW_KINDS, TIME_BOUND_STAGE, TITLE_DISTINCT_SHARE, type TeachesFeature, type TemplateAgent, type TemplateAgentBinding, type TemplateAgentCopyRequest, type TemplateAgentQuestion, type TemplateAgentVariable, type TemplateAssetRow, type TemplateAttachment, type TemplateAudience, type TemplateAutomation, type TemplateBooking, type TemplateBookingWindow, type TemplateCalendarView, type TemplateCard, type TemplateChecklist, type TemplateChecklistStep, type TemplateConfidential, type TemplateConfidentialReader, type TemplateDashboard, type TemplateDashboardBlock, type TemplateDeclaration, type TemplateDigest, type TemplateDimensionOverride, type TemplateDimensions, type TemplateDocument, type TemplateDoorAnswer, type TemplateDoorRun, type TemplateDrillDown, type TemplateDrillPath, type TemplateExtra, type TemplateExtraAgent, type TemplateExtraAgentVariable, type TemplateExtraKind, type TemplateFamilyDoor, type TemplateField, type TemplateFootprint, type TemplateForm, type TemplateFormField, type TemplateFoundation, type TemplateGalleryView, type TemplateGridView, type TemplateGuideStep, type TemplateHostExtras, type TemplateInstallPlan, type TemplateJob, type TemplateKanbanView, type TemplateMadeKind, type TemplateMeasureOverride, type TemplateMergeBinding, type TemplateNotification, type TemplatePlanAgent, type TemplatePlanBinding, type TemplatePlanDoor, type TemplatePlanExtraAgent, type TemplatePlanStep, type TemplatePortal, type TemplatePortalTable, type TemplateProvenance, type TemplateRowAction, type TemplateSource, type TemplateSpec, type TemplateSpecWithAttachments, type TemplateStageRules, type TemplateStatus, type TemplateTable, type TemplateTableSettings, type TemplateTimelineView, type TemplateTryIt, type TemplateVerdict, type TemplateView, type TemplateViewKind, type TemplateViewSort, type TemplateWorkflow, type UseCaseSingulars, type ValidateOptions, type WalkAction, type WalkAssertion, type WalkImport, type WalkMove, type WalkStep, agentCopyRequest, allTables, anyOfWhere, assertTemplate, attachmentProblems, automationHeld, blockTable, bookingArgs, bookingColumnsProblem, capabilitiesUsed, capabilityStatus, checklistSpec, choiceDisplayFormat, compileHostExtras, compileInstallPlan, confidentialPending, confidentialRequests, dashboardBlocks, deferredRelationFields, deferredRelations, derivedFieldSpec, digestSpec, documentBody, domainsIn, drillDownDashboard, evalFormula, extrasProblems, footprintOf, foreignTextProblems, formArgs, formulaFieldSpec, formulaOrder, formulaRefs, foundationTokens, isSelfDeclaredField, isTimedField, membersAddRowsSteps, normalizeForPhones, notificationParts, numberText, numberedStreet, parseFormula, parseNumeric, peopleOf, phonesOutsideFictionalRange, planTables, portalArgs, relationFieldSpec, relationPatches, relativeHasTime, requiredCircleProblem, resolveDateToken, resolveRelativeDates, rowActionList, rowLevels, rowsFor, ruleBreak, runTemplateDoor, selfDeclaredFieldSpec, shellsPayload, stageFieldOf, stageRulesSpec, storeAggregate, storeFilterMatches, storeText, tableSettingsProblems, tableShellPayload, templateCard, templateDeclaration, templateText, timedFieldSpec, toUseCase, unwrap, useCaseProblemsOf, validateTemplate, viewMatches, viewSpec, whenRule, zoneOffset };
594
+ export { AgentSnapshotRow, type AggregateOutcome, type CapabilityStatus, CapabilityWord, DESIGNATED_REAL_NUMBERS, type DerivedUseCase, FORMULA_FUNCTIONS, INSTALL_PLAN_VERSION, MAIN_TABLE_ROWS_MAX, MAIN_TABLE_ROWS_MIN, PUBLIC_MAIL_DOMAINS, RECORDS_UI_CALENDAR_MODES, RECORDS_UI_FIELD_SURFACES, RECORDS_UI_VIEW_LAYOUTS, SERVER_DATE_GRAMMAR, type SeedRow, SharedBlockId, TABLES_MAX, TABLES_MIN, TEMPLATE_PLAN_DOORS, TIME_BOUND_STAGE, TITLE_DISTINCT_SHARE, TemplateAgent, type TemplateAgentBinding, type TemplateAgentCopyRequest, type TemplateAssetRow, type TemplateAttachment, TemplateAutomation, TemplateBooking, type TemplateCard, TemplateChecklist, TemplateDashboard, type TemplateDeclaration, TemplateDigest, TemplateDimensions, TemplateDocument, type TemplateDoorAnswer, type TemplateDoorRun, TemplateDrillDown, type TemplateFamilyDoor, TemplateField, TemplateFootprint, TemplateForm, type TemplateHostExtras, type TemplateInstallPlan, type TemplateMadeKind, TemplateMergeBinding, TemplateNotification, type TemplatePlanAgent, type TemplatePlanBinding, type TemplatePlanDoor, type TemplatePlanExtraAgent, type TemplatePlanStep, TemplatePortal, TemplateRowAction, TemplateSpec, type TemplateSpecWithAttachments, TemplateStageRules, type TemplateStatus, TemplateTable, TemplateTryIt, type TemplateVerdict, TemplateView, TemplateWorkflow, type ValidateOptions, agentCopyRequest, allTables, anyOfWhere, assertTemplate, attachmentProblems, automationHeld, blockTable, bookingArgs, bookingColumnsProblem, capabilitiesUsed, capabilityStatus, checklistSpec, choiceDisplayFormat, compileHostExtras, compileInstallPlan, dashboardBlocks, deferredRelationFields, deferredRelations, derivedFieldSpec, digestSpec, documentBody, domainsIn, drillDownDashboard, evalFormula, extrasProblems, foreignTextProblems, formArgs, formulaFieldSpec, formulaOrder, formulaRefs, foundationTokens, isSelfDeclaredField, isTimedField, normalizeForPhones, notificationParts, numberText, numberedStreet, parseFormula, parseNumeric, peopleOf, phonesOutsideFictionalRange, planTables, portalArgs, relationFieldSpec, relationPatches, relativeHasTime, requiredCircleProblem, resolveDateToken, resolveRelativeDates, rowActionList, rowLevels, rowsFor, ruleBreak, runTemplateDoor, selfDeclaredFieldSpec, shellsPayload, stageFieldOf, stageRulesSpec, storeAggregate, storeFilterMatches, storeText, tableShellPayload, templateCard, templateDeclaration, templateText, timedFieldSpec, toUseCase, unwrap, useCaseProblemsOf, validateTemplate, viewMatches, viewSpec, zoneOffset };