@ai-matrx/records 0.29.0 → 0.30.0

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.
@@ -2198,6 +2198,38 @@ var PLACEHOLDER_PATTERNS = [
2198
2198
  why: "A repeated stand-in person is the tell that nobody modelled the domain.",
2199
2199
  instead: "Synthesize varied, plausible people who belong to nobody \u2014 and never copy a real person."
2200
2200
  },
2201
+ {
2202
+ // THE CHAIR'S RULING, 2026-09-21. People in a template are fictional but
2203
+ // REALISTIC, and a realistic person's mailbox is a mailbox — not a mailbox
2204
+ // with a counter welded to the end of it. `linda.reyes0@…`,
2205
+ // `wei.singh.m34@…` are the tell that a loop wrote the row, and the owner
2206
+ // reads a whole column of them as one fake person repeated.
2207
+ //
2208
+ // NARROW ON PURPOSE: it fires only when the local part is name-shaped
2209
+ // (two or more words joined by . _ or -) AND ends in a bare counter. That
2210
+ // is exactly the generator's signature and leaves the real mailboxes a
2211
+ // business has — `support365@`, `ap2@`, `frontdesk@` — alone.
2212
+ id: "suffixed-mailbox",
2213
+ test: /\b[a-z]+(?:[._-][a-z]+)+\d{1,3}@/gi,
2214
+ why: "A mailbox whose name ends in a counter (linda.reyes0@, wei.singh.m34@) is a generated row wearing a person's name.",
2215
+ instead: "Give each person their own mailbox on the fictional business's own domain \u2014 'linda.reyes@handsandhopealliance.org' \u2014 and vary the people instead of numbering one."
2216
+ },
2217
+ {
2218
+ // THE CHAIR'S RULING, 2026-09-21. "Test fixture" is a CLASSIFICATION, and a
2219
+ // classification lives in the organization's kind/metadata — the
2220
+ // `test_fixture` flag in its settings, which is how cleanup finds it. It is
2221
+ // never part of a NAME, because a name is what the owner reads on the
2222
+ // screen and "Birchwood Ave Renovation (test fixture)" tells him the
2223
+ // product is a rehearsal.
2224
+ //
2225
+ // The settings KEY is the right place, so a line that is writing the key is
2226
+ // exempt; a line that is writing the words into text is not.
2227
+ id: "fixture-in-name",
2228
+ test: /\(\s*test\s+fixture\s*\)|\btest[\s_-]fixture\b|\bfixture[\s_-]org(?:anization|anisation)?\b/gi,
2229
+ unlessLineMatches: /["'`]?test_fixture["'`]?\s*[:=]|\bp_settings\b|\bcleanupTag\b|\bsettings\.[a-z_]*fixture\b/i,
2230
+ why: "'Test fixture' is a classification, not a name. In a name it tells the owner the screen he is looking at is a rehearsal.",
2231
+ instead: "Name the organization after the business the use case is about, and carry the classification in its settings (`test_fixture: true`), which is also how cleanup finds it."
2232
+ },
2201
2233
  {
2202
2234
  id: "keyboard-mash",
2203
2235
  test: /\basdf+\b|\bqwerty\b|\bxxx+\b|\btodo name\b|\bfixme\b|\btbd\b/gi,
@@ -2233,6 +2265,7 @@ function describePlaceholder(hit) {
2233
2265
  var STORAGE_MODES = ["light", "heavy"];
2234
2266
  var PARITY_FIELD_TYPES = [
2235
2267
  { parity_type: "attachment", behavior: "relation", made_of: "REC-31: a File record reached through a relation, target the kernel `File` Table" },
2268
+ { parity_type: "checkbox", behavior: "boolean", made_of: "a ticked or unticked answer, stored as a REAL boolean \u2014 and a record that never answered holds neither, so filters and group-by see three states, not two" },
2236
2269
  { parity_type: "currency", behavior: "range", made_of: "FLD-N-1: a number whose UNIT is the currency and whose format is currency \u2014 on the Field, never in presentation" },
2237
2270
  { parity_type: "datetime", behavior: "range", made_of: "a range of kind date or datetime \u2014 the dated modifier says the VALUES are dated, which is a different question" },
2238
2271
  { parity_type: "email", behavior: "text", made_of: "text whose format is email" },
@@ -2286,6 +2319,21 @@ var MIN_ROWS_IN_PRIMARY_TABLE = 5;
2286
2319
  function fieldsByKey(table) {
2287
2320
  return new Map(table.fields.map((f) => [f.key, f]));
2288
2321
  }
2322
+ var FIXTURE_IN_NAME = /\(\s*test\s+fixture\s*\)|\btest[\s_-]fixture\b|^\s*fixtures?\b/i;
2323
+ function nameFields(useCase5) {
2324
+ const out = [
2325
+ ["business.name", useCase5.business?.name],
2326
+ ["business.legalName", useCase5.business?.legalName],
2327
+ ["form.name", useCase5.form?.name],
2328
+ ["pipeline.name", useCase5.pipeline?.name]
2329
+ ];
2330
+ useCase5.tables?.forEach((table, ti) => {
2331
+ out.push([`tables[${ti}].name`, table.name]);
2332
+ out.push([`tables[${ti}].labelSingular`, table.labelSingular]);
2333
+ out.push([`tables[${ti}].labelPlural`, table.labelPlural]);
2334
+ });
2335
+ return out;
2336
+ }
2289
2337
  function validateUseCase(useCase5) {
2290
2338
  const problems = [];
2291
2339
  const say = (at, says) => problems.push({ at, says });
@@ -2302,6 +2350,15 @@ function validateUseCase(useCase5) {
2302
2350
  for (const hit of findPlaceholders(JSON.stringify(useCase5, null, 1))) {
2303
2351
  say(useCase5.id, describePlaceholder(hit));
2304
2352
  }
2353
+ for (const [at, value] of nameFields(useCase5)) {
2354
+ if (!value) continue;
2355
+ if (FIXTURE_IN_NAME.test(value)) {
2356
+ say(
2357
+ at,
2358
+ `"${value}" carries the test-fixture classification in a name. Name it after the business this use case is about, and carry the classification where it belongs \u2014 \`test_fixture: true\` in the organization's settings, which is also how cleanup finds it (never by a junk name).`
2359
+ );
2360
+ }
2361
+ }
2305
2362
  if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(useCase5.id ?? "")) {
2306
2363
  say("id", `The id "${useCase5.id}" should be kebab-case, like "harbor-dental-new-patient-intake".`);
2307
2364
  }