@ai-matrx/records 0.72.12 → 0.72.23

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 +66 -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 +2681 -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 +2658 -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 +59 -24
  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 +59 -24
  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
@@ -1020,4 +1020,4 @@ interface RecordsConfig {
1020
1020
  knownDoors?: readonly string[];
1021
1021
  }
1022
1022
 
1023
- export { type SubscriptionBlock as $, type AggregateCompare as A, type BookingSummary as B, type DashboardTarget as C, type DashboardSummary as D, type DashboardTargetBase as E, type FormSummary as F, type DashboardTargetOp as G, type DashboardTargetResult as H, type DashboardTotals as I, type RecordsActor as J, type RecordsChangeSink as K, type RecordsErrorSink as L, type MySubscription as M, type RecordsFilter as N, type RecordsRealtimePort as O, type RecordsResolverPort as P, type QuietHours as Q, type RecordsConfig as R, type StoreFilter as S, type RecordsResponse as T, type RecordsTableQuery as U, type Rule as V, type RuleAnswer as W, type RuleExpression as X, type SavedViewColorBy as Y, type SavedViewDefinition as Z, type SavedViewLayout as _, type BookingAvailability as a, bookingPath as a0, callersTimeZone as a1, hasQuietHours as a2, isRuleFilter as a3, liftWithheld as a4, measureKey as a5, publicFormPath as a6, stableFilterKey as a7, withCallersClock as a8, type BookingDeclared as b, type DashboardBlock as c, type RecordFilter as d, type AggregateBucket as e, type DashboardRunResult as f, type StuckRow as g, type AggregateMeasure as h, type AggregateRow as i, type Subscription as j, type SubscriptionSpec as k, type DigestPreview as l, type SavedViewRow as m, type SavedViewSpecIn as n, type RowTemplateRow as o, type DashboardBlockKind as p, type AggregateFilter as q, type SubscriptionCadence as r, type AggregateOperation as s, type RecordsDataSource as t, type AggregateCompareKind as u, type AggregateCompareWindows as v, type AggregateDelta as w, type AggregateWindow as x, type BookingWindow as y, type DashboardBlockResult as z };
1023
+ export { type SubscriptionBlock as $, type AggregateOperation as A, type BookingSummary as B, type DashboardTarget as C, type DashboardBlockKind as D, type DashboardTargetBase as E, type FormSummary as F, type DashboardTargetOp as G, type DashboardTargetResult as H, type DashboardTotals as I, type RecordsActor as J, type RecordsChangeSink as K, type RecordsErrorSink as L, type MySubscription as M, type RecordsFilter as N, type RecordsRealtimePort as O, type RecordsResolverPort as P, type QuietHours as Q, type RecordsConfig as R, type SubscriptionCadence as S, type RecordsResponse as T, type RecordsTableQuery as U, type Rule as V, type RuleAnswer as W, type RuleExpression as X, type SavedViewColorBy as Y, type SavedViewDefinition as Z, type SavedViewLayout as _, type AggregateFilter as a, bookingPath as a0, callersTimeZone as a1, hasQuietHours as a2, isRuleFilter as a3, liftWithheld as a4, measureKey as a5, publicFormPath as a6, stableFilterKey as a7, withCallersClock as a8, type AggregateMeasure as b, type AggregateBucket as c, type StoreFilter as d, type BookingAvailability as e, type BookingDeclared as f, type DashboardSummary as g, type DashboardBlock as h, type RecordFilter as i, type AggregateCompare as j, type DashboardRunResult as k, type StuckRow as l, type AggregateRow as m, type Subscription as n, type SubscriptionSpec as o, type DigestPreview as p, type SavedViewRow as q, type SavedViewSpecIn as r, type RowTemplateRow as s, type RecordsDataSource as t, type AggregateCompareKind as u, type AggregateCompareWindows as v, type AggregateDelta as w, type AggregateWindow as x, type BookingWindow as y, type DashboardBlockResult as z };
@@ -1020,4 +1020,4 @@ interface RecordsConfig {
1020
1020
  knownDoors?: readonly string[];
1021
1021
  }
1022
1022
 
1023
- export { type SubscriptionBlock as $, type AggregateCompare as A, type BookingSummary as B, type DashboardTarget as C, type DashboardSummary as D, type DashboardTargetBase as E, type FormSummary as F, type DashboardTargetOp as G, type DashboardTargetResult as H, type DashboardTotals as I, type RecordsActor as J, type RecordsChangeSink as K, type RecordsErrorSink as L, type MySubscription as M, type RecordsFilter as N, type RecordsRealtimePort as O, type RecordsResolverPort as P, type QuietHours as Q, type RecordsConfig as R, type StoreFilter as S, type RecordsResponse as T, type RecordsTableQuery as U, type Rule as V, type RuleAnswer as W, type RuleExpression as X, type SavedViewColorBy as Y, type SavedViewDefinition as Z, type SavedViewLayout as _, type BookingAvailability as a, bookingPath as a0, callersTimeZone as a1, hasQuietHours as a2, isRuleFilter as a3, liftWithheld as a4, measureKey as a5, publicFormPath as a6, stableFilterKey as a7, withCallersClock as a8, type BookingDeclared as b, type DashboardBlock as c, type RecordFilter as d, type AggregateBucket as e, type DashboardRunResult as f, type StuckRow as g, type AggregateMeasure as h, type AggregateRow as i, type Subscription as j, type SubscriptionSpec as k, type DigestPreview as l, type SavedViewRow as m, type SavedViewSpecIn as n, type RowTemplateRow as o, type DashboardBlockKind as p, type AggregateFilter as q, type SubscriptionCadence as r, type AggregateOperation as s, type RecordsDataSource as t, type AggregateCompareKind as u, type AggregateCompareWindows as v, type AggregateDelta as w, type AggregateWindow as x, type BookingWindow as y, type DashboardBlockResult as z };
1023
+ export { type SubscriptionBlock as $, type AggregateOperation as A, type BookingSummary as B, type DashboardTarget as C, type DashboardBlockKind as D, type DashboardTargetBase as E, type FormSummary as F, type DashboardTargetOp as G, type DashboardTargetResult as H, type DashboardTotals as I, type RecordsActor as J, type RecordsChangeSink as K, type RecordsErrorSink as L, type MySubscription as M, type RecordsFilter as N, type RecordsRealtimePort as O, type RecordsResolverPort as P, type QuietHours as Q, type RecordsConfig as R, type SubscriptionCadence as S, type RecordsResponse as T, type RecordsTableQuery as U, type Rule as V, type RuleAnswer as W, type RuleExpression as X, type SavedViewColorBy as Y, type SavedViewDefinition as Z, type SavedViewLayout as _, type AggregateFilter as a, bookingPath as a0, callersTimeZone as a1, hasQuietHours as a2, isRuleFilter as a3, liftWithheld as a4, measureKey as a5, publicFormPath as a6, stableFilterKey as a7, withCallersClock as a8, type AggregateMeasure as b, type AggregateBucket as c, type StoreFilter as d, type BookingAvailability as e, type BookingDeclared as f, type DashboardSummary as g, type DashboardBlock as h, type RecordFilter as i, type AggregateCompare as j, type DashboardRunResult as k, type StuckRow as l, type AggregateRow as m, type Subscription as n, type SubscriptionSpec as o, type DigestPreview as p, type SavedViewRow as q, type SavedViewSpecIn as r, type RowTemplateRow as s, type RecordsDataSource as t, type AggregateCompareKind as u, type AggregateCompareWindows as v, type AggregateDelta as w, type AggregateWindow as x, type BookingWindow as y, type DashboardBlockResult as z };
@@ -1,5 +1,5 @@
1
1
  import { n as ReadRow, g as Timestamp, U as Uuid, h as RecordDocument, R as RelationFlavor, O as OnDelete, aK as RelationBinding, f as RelationCardinality, i as RecordsResult, r as StoredRecord, q as Field, az as ParityFieldType, T as TableType, a as TableDisplay, S as StorageMode, b0 as TableOrigin, z as RecordsError } from './field-CekLWOPw.js';
2
- import { t as RecordsDataSource } from './ports-Bhu2Q3V0.js';
2
+ import { t as RecordsDataSource } from './ports-Df3VghxK.js';
3
3
 
4
4
  /**
5
5
  * THE TWO LANES THE ARCHIVED-ITEMS LAW NAMES (Arman, 2026-09-09) — the same
@@ -1,5 +1,5 @@
1
1
  import { n as ReadRow, g as Timestamp, U as Uuid, h as RecordDocument, R as RelationFlavor, O as OnDelete, aK as RelationBinding, f as RelationCardinality, i as RecordsResult, r as StoredRecord, q as Field, az as ParityFieldType, T as TableType, a as TableDisplay, S as StorageMode, b0 as TableOrigin, z as RecordsError } from './field-CekLWOPw.cjs';
2
- import { t as RecordsDataSource } from './ports-DKBvsoya.cjs';
2
+ import { t as RecordsDataSource } from './ports-DKOk7AT2.cjs';
3
3
 
4
4
  /**
5
5
  * THE TWO LANES THE ARCHIVED-ITEMS LAW NAMES (Arman, 2026-09-09) — the same
@@ -37,6 +37,7 @@ __export(templates_exports, {
37
37
  RECORDS_UI_FIELD_SURFACES: () => RECORDS_UI_FIELD_SURFACES,
38
38
  RECORDS_UI_VIEW_LAYOUTS: () => RECORDS_UI_VIEW_LAYOUTS,
39
39
  RELATIVE_DATE: () => RELATIVE_DATE,
40
+ RESOLVABLE_FIELD_TYPE_WORDS: () => RESOLVABLE_FIELD_TYPE_WORDS,
40
41
  SERVER_DATE_GRAMMAR: () => SERVER_DATE_GRAMMAR,
41
42
  SHARED_BLOCKS: () => SHARED_BLOCKS,
42
43
  SHARED_BLOCK_IDS: () => SHARED_BLOCK_IDS,
@@ -3601,6 +3602,12 @@ function validateTemplate(raw, options = {}) {
3601
3602
  seedLooks.add(p);
3602
3603
  problems.push(p);
3603
3604
  };
3605
+ const galleryBar = /* @__PURE__ */ new WeakSet();
3606
+ const sayGallery = (at, says) => {
3607
+ const p = { at, says };
3608
+ galleryBar.add(p);
3609
+ problems.push(p);
3610
+ };
3604
3611
  const tz = raw.business?.timezone || "UTC";
3605
3612
  const tablesRaw = allTables(raw);
3606
3613
  const ISO_DAY = /\b\d{4}-\d{2}-\d{2}\b/;
@@ -3923,7 +3930,7 @@ function validateTemplate(raw, options = {}) {
3923
3930
  say(`${tat}.rows`, `Only ${titles.size} of ${table.rows.length} rows have a title of their own; a list of look-alike names reads as generated.`);
3924
3931
  }
3925
3932
  });
3926
- if (!hasLookupOrRollup) say("tables", "At least one relationship has to be read across: add a lookup or a rollup through a relation field.");
3933
+ if (!hasLookupOrRollup) sayGallery("tables", "At least one relationship has to be read across: add a lookup or a rollup through a relation field.");
3927
3934
  if (main) {
3928
3935
  const normTitle = (v) => (storeText(v) ?? "").toLowerCase().replace(/\s+/g, " ").trim();
3929
3936
  const rows = main.rows;
@@ -3991,8 +3998,8 @@ function validateTemplate(raw, options = {}) {
3991
3998
  else surfaces.set(token, { at, ...table ? { table } : {} });
3992
3999
  };
3993
4000
  const views = spec.views ?? [];
3994
- if (views.length < 3) say("views", `A template shows at least three views; this one has ${views.length}.`);
3995
- if (!views.some((v) => v.kind === "grid")) say("views", "One of the views is a grid \u2014 the table everyone recognises.");
4001
+ if (views.length < 3) sayGallery("views", `A template shows at least three views; this one has ${views.length}.`);
4002
+ if (!views.some((v) => v.kind === "grid")) sayGallery("views", "One of the views is a grid \u2014 the table everyone recognises.");
3996
4003
  views.forEach((view, i) => {
3997
4004
  const at = `views[${i}] (${view.token})`;
3998
4005
  claim(view.token, at, view.table);
@@ -4118,7 +4125,7 @@ function validateTemplate(raw, options = {}) {
4118
4125
  }
4119
4126
  };
4120
4127
  const extras = spec.extras ?? [];
4121
- if (extras.length < 2) say("extras", `A template carries at least two extras; this one has ${extras.length}.`);
4128
+ if (extras.length < 2) sayGallery("extras", `A template carries at least two extras; this one has ${extras.length}.`);
4122
4129
  const formTokens = new Set(forms.map((f) => f.token));
4123
4130
  const viewTokens = new Set(views.map((v) => v.token));
4124
4131
  const docTokens = new Set(extras.filter((e) => e.kind === "document").map((e) => e.token));
@@ -4467,7 +4474,8 @@ function validateTemplate(raw, options = {}) {
4467
4474
  if (here >= 0 && Number.isFinite(firstWhen) && here < firstWhen && !TERMINAL_STAGE.test(st)) {
4468
4475
  for (const k of rule.filled ?? []) {
4469
4476
  if (!/^(?:datetime|date|checkbox|signature|attachment)$/.test(fieldOf(table, k)?.parityType ?? "")) continue;
4470
- if (filled(row.values?.[k])) say(at, `"${row.key}" is ${st}, but already has "${fieldOf(table, k)?.label ?? k}", which only a ${rule.when.join("/")} record carries. Leave it empty until the record gets there.`);
4477
+ const v = row.values?.[k];
4478
+ if (fieldOf(table, k)?.parityType === "checkbox" ? v === true || v === "true" : filled(v)) say(at, `"${row.key}" is ${st}, but already has "${fieldOf(table, k)?.label ?? k}", which only a ${rule.when.join("/")} record carries. Leave it empty until the record gets there.`);
4471
4479
  }
4472
4480
  }
4473
4481
  if (!rule.when.includes(st)) continue;
@@ -4805,6 +4813,7 @@ function validateTemplate(raw, options = {}) {
4805
4813
  }
4806
4814
  }
4807
4815
  adds += 1;
4816
+ for (const f of table.fields) if (f.default !== void 0 && !isComputed(f) && values[f.key] === void 0) values[f.key] = f.default;
4808
4817
  const added = { key: `walk-${i}-${ri}`, values };
4809
4818
  const landed = rules ? storeText(values[rules.stageField]) : null;
4810
4819
  for (const k of landed ? rules?.requires?.[landed] ?? [] : []) if (!filled(values[k])) say(`${at}.action.rows[${ri}]`, `The new row "${keyValue}" lands in "${landed}", which needs "${k}" filled; the store would refuse it.`);
@@ -5128,7 +5137,8 @@ function validateTemplate(raw, options = {}) {
5128
5137
  const at = `tables (${t.token}).fields (${f.key})`;
5129
5138
  const text2 = `${f.key} ${norm(f.label)}`;
5130
5139
  const e = effective(t.token, f);
5131
- const criminalCharges = /(^|_)charges?($|_)/.test(f.key) && behaviorOf(f) === "text";
5140
+ const billingTable = /(invoice|bill|statement|receipt|payment|charge|fee|order|account)/i.test(`${t.token} ${t.labelSingular}`);
5141
+ const criminalCharges = /(^|_)charges?($|_)/.test(f.key) && behaviorOf(f) === "text" && !billingTable;
5132
5142
  const phoneLike = behaviorOf(f) === "text" && /\b(cell|mobile|phone)\b/.test(norm(f.label));
5133
5143
  const personal = PERSONAL_ONLY.test(f.key) || /\b(medical conditions?|medications?|diagnos[ie]s)\b/.test(norm(f.label));
5134
5144
  const floored = (RESTRICTED_KEY.test(f.key) || RESTRICTED_LABEL.test(norm(f.label)) || criminalCharges) && (!personal || holdsPeople(t));
@@ -5432,7 +5442,8 @@ ${e.body}`.matchAll(MERGE_TOKEN)].map((m) => m[1]));
5432
5442
  const qq = agent.question;
5433
5443
  const ask = norm(qq.ask);
5434
5444
  const words = (t) => norm(t).split(" ").filter((w) => w.length >= 4);
5435
- const mentions = (t) => words(t).some((w) => ask.includes(w.replace(/s$/, "")));
5445
+ const askWords = new Set(ask.split(" "));
5446
+ const mentions = (t) => !!norm(t) && ask.includes(norm(t)) || words(t).some((w) => ask.includes(w.replace(/s$/, ""))) || words(t).length === 0 && norm(t).split(" ").filter(Boolean).some((w) => w.length >= 3 && (askWords.has(w) || askWords.has(`${w}s`)));
5436
5447
  for (const [k, v] of Object.entries(qq.expect.filter ?? {})) {
5437
5448
  if (typeof v === "string" && !mentions(v) && !ask.includes(norm(v))) say("agent.question.ask", `It filters on ${k} = "${v}", and the question never says so.`);
5438
5449
  }
@@ -5513,7 +5524,8 @@ ${e.body}`.matchAll(MERGE_TOKEN)].map((m) => m[1]));
5513
5524
  const named = (t) => {
5514
5525
  if (!t) return false;
5515
5526
  if (says.includes(norm(t))) return true;
5516
- const words = [...new Set(norm(t).split(" ").filter((w) => w.length >= 4))];
5527
+ const long = [...new Set(norm(t).split(" ").filter((w) => w.length >= 4))];
5528
+ const words = long.length ? long : [...new Set(norm(t).split(" ").filter((w) => w.length >= 2))];
5517
5529
  const said = new Set(says.split(" "));
5518
5530
  return words.length > 0 && words.filter((w) => said.has(w) || said.has(`${w}s`)).length >= Math.min(2, words.length);
5519
5531
  };
@@ -5929,7 +5941,7 @@ ${e.body}`.matchAll(MERGE_TOKEN)].map((m) => m[1]));
5929
5941
  if (bothDates && !datesStated) say(`${at}.childDates`, `"${t.token}" and its ${rel.label.toLowerCase()} ("${parent.token}") both carry dates; say how they agree, e.g. {"relation": "${rel.key}", "field": "<this table's date>", "parentField": "<${parent.token}'s date>"} or say why they are independent in independentOf {"${rel.key}": "<reason>"}.`);
5930
5942
  if (bothStatus && !statusStated) say(`${at}.statusAgrees`, `"${t.token}" and its ${rel.label.toLowerCase()} ("${parent.token}") both carry a status; say which child statuses need which parent status (statusAgrees), e.g. a Closed deal means a Sold listing.`);
5931
5943
  }
5932
- for (const f of t.fields.filter((x) => isNumber(x) && !isComputed(x) && /(^|_)(count|roster_size|size|number_of|enrolled|headcount|players|members)($|_)/.test(x.key))) {
5944
+ for (const f of t.fields.filter((x) => isNumber(x) && !isComputed(x) && /(^|_)(count|roster_size|team_size|class_size|number_of|enrolled|headcount|players|members)($|_)/.test(x.key))) {
5933
5945
  const linked = own.find((c) => c.fields.some((cf) => isRelation(cf) && cf.relationTarget === t.token));
5934
5946
  const declared = (t.countMatches ?? []).find((c) => c.field === f.key);
5935
5947
  const linkers = own.filter((c) => c.fields.some((cf) => isRelation(cf) && cf.relationTarget === t.token)).map((c) => c.labelPlural.toLowerCase());
@@ -5964,7 +5976,7 @@ ${e.body}`.matchAll(MERGE_TOKEN)].map((m) => m[1]));
5964
5976
  const describeOwes = (p) => {
5965
5977
  const root = p.at.split(/[.\s[(]/)[0];
5966
5978
  if (GALLERY_ONLY_ROOTS.includes(root)) return false;
5967
- if (seedLooks.has(p)) return false;
5979
+ if (seedLooks.has(p) || galleryBar.has(p)) return false;
5968
5980
  if (/^tables\[\d+\] \([^)]*\)\.rows$/.test(p.at)) return false;
5969
5981
  return true;
5970
5982
  };
@@ -6063,7 +6075,14 @@ function compileInstallPlan(written) {
6063
6075
  const attachments = written.attachments ?? [];
6064
6076
  const attachmentKeys = new Set(attachments.map((a) => a.key));
6065
6077
  const spec = tokenizeValues({ ...written, attachments: void 0 }, attachmentKeys);
6066
- const tables = allTables(spec);
6078
+ const bound = new Map(allTables(spec).filter((t) => t.bindsTo?.tableId).map((t) => [t.token, t.bindsTo]));
6079
+ const has = (token, key) => bound.get(token)?.fields.includes(key) ?? false;
6080
+ const tables = allTables(spec).map((t) => {
6081
+ if (bound.has(t.token)) return { ...t, rows: [] };
6082
+ const toBound = t.fields.filter((f) => f.parityType === "relation" && f.relationTarget && bound.has(f.relationTarget)).map((f) => f.key);
6083
+ if (!toBound.length) return t;
6084
+ return { ...t, rows: t.rows.map((r) => ({ ...r, values: Object.fromEntries(Object.entries(r.values ?? {}).filter(([k]) => !toBound.includes(k))) })) };
6085
+ });
6067
6086
  const steps = [];
6068
6087
  const tableRef = (token) => {
6069
6088
  if (!tables.some((t) => t.token === token)) throw new Error(`The template names a table "${token}" it does not have.`);
@@ -6093,6 +6112,18 @@ function compileInstallPlan(written) {
6093
6112
  }
6094
6113
  }
6095
6114
  for (const t of tables) {
6115
+ if (bound.has(t.token)) {
6116
+ for (const f of t.fields.filter((x) => !DERIVED.has(x.parityType) && x.parityType !== "formula" && x.parityType !== "relation" && !isSelfDeclaredField(x) && !has(t.token, x.key))) {
6117
+ steps.push({
6118
+ label: `bound.${t.token}.${f.key}`,
6119
+ door: "field_declare",
6120
+ args: { p_organization_id: "${org}", p_table_id: tableRef(t.token), p_spec: selfDeclaredFieldSpec(f) },
6121
+ save: { [`fields.${t.token}.${f.key}`]: [] },
6122
+ made: [{ kind: "field", ref: `fields.${t.token}.${f.key}`, table: `tables.${t.token}` }]
6123
+ });
6124
+ }
6125
+ continue;
6126
+ }
6096
6127
  steps.push({
6097
6128
  label: `tables.${t.token}`,
6098
6129
  door: "table_from_example",
@@ -6103,7 +6134,7 @@ function compileInstallPlan(written) {
6103
6134
  }
6104
6135
  steps.push(...membersAddRowsSteps(spec, tableRef));
6105
6136
  for (const t of tables) {
6106
- for (const f of t.fields.filter((x) => x.parityType === "relation" && x.relationTarget)) {
6137
+ for (const f of t.fields.filter((x) => x.parityType === "relation" && x.relationTarget && !has(t.token, x.key))) {
6107
6138
  steps.push({
6108
6139
  label: `relations.${t.token}.${f.key}`,
6109
6140
  door: "field_declare",
@@ -6114,7 +6145,7 @@ function compileInstallPlan(written) {
6114
6145
  }
6115
6146
  }
6116
6147
  for (const t of tables) {
6117
- for (const f of t.fields.filter(isSelfDeclaredField)) {
6148
+ for (const f of t.fields.filter((x) => isSelfDeclaredField(x) && !has(t.token, x.key))) {
6118
6149
  steps.push({
6119
6150
  label: `self_declared.${t.token}.${f.key}`,
6120
6151
  door: "field_declare",
@@ -6150,7 +6181,7 @@ function compileInstallPlan(written) {
6150
6181
  }
6151
6182
  }
6152
6183
  for (const t of tables) {
6153
- for (const f of t.fields.filter((x) => DERIVED.has(x.parityType))) {
6184
+ for (const f of t.fields.filter((x) => DERIVED.has(x.parityType) && !has(t.token, x.key))) {
6154
6185
  steps.push({
6155
6186
  label: `derived.${t.token}.${f.key}`,
6156
6187
  door: "field_declare",
@@ -6161,7 +6192,7 @@ function compileInstallPlan(written) {
6161
6192
  }
6162
6193
  }
6163
6194
  for (const t of tables) {
6164
- for (const f of formulaOrder(t)) {
6195
+ for (const f of formulaOrder(t).filter((x) => !has(t.token, x.key))) {
6165
6196
  steps.push({
6166
6197
  label: `formula.${t.token}.${f.key}`,
6167
6198
  door: "field_declare",
@@ -6187,7 +6218,7 @@ function compileInstallPlan(written) {
6187
6218
  saveEach: { array: [], key: ["data", "key"], value: ["id"], prefix: `fields.${token}.` }
6188
6219
  });
6189
6220
  }
6190
- for (const d of spec.dimensions) {
6221
+ for (const d of spec.dimensions.filter((x) => !bound.has(x.table))) {
6191
6222
  const overrides = {};
6192
6223
  if (d.dimensions) overrides["dimensions"] = d.dimensions;
6193
6224
  if (d.measures) overrides["measures"] = d.measures;
@@ -6344,18 +6375,22 @@ function compileInstallPlan(written) {
6344
6375
  });
6345
6376
  }
6346
6377
  const host = compileHostExtras(spec);
6378
+ const agent = spec.agent;
6347
6379
  return {
6348
6380
  planVersion: INSTALL_PLAN_VERSION,
6349
6381
  timezone: spec.business.timezone || "UTC",
6350
6382
  steps,
6351
- agent: {
6352
- platformAgent: spec.agent.platformAgent,
6353
- name: spec.agent.name,
6354
- bindings: spec.agent.variables.map((v) => {
6355
- const binding = host.agentBindings.get(v.name);
6356
- return { variable: v.name, tableToken: v.table, describes: v.describes, ...binding ? { binding } : {} };
6357
- })
6358
- },
6383
+ ...agent?.platformAgent ? {
6384
+ agent: {
6385
+ platformAgent: agent.platformAgent,
6386
+ name: agent.name,
6387
+ bindings: (agent.variables ?? []).map((v) => {
6388
+ const binding = host.agentBindings.get(v.name);
6389
+ return { variable: v.name, tableToken: v.table, describes: v.describes, ...binding ? { binding } : {} };
6390
+ })
6391
+ }
6392
+ } : {},
6393
+ ...bound.size ? { ids: Object.fromEntries([...bound].map(([token, b]) => [`ref:tables.${token}`, b.tableId])) } : {},
6359
6394
  ...host.extras
6360
6395
  };
6361
6396
  }