@fuzdev/fuz_app 0.98.0 → 0.99.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.
@@ -125,9 +125,25 @@ export declare const generate_phase_handlers: (spec: ActionSpecUnion, executor:
125
125
  }) => string;
126
126
  /** "DO NOT EDIT" banner naming the gen producer. */
127
127
  export declare const create_banner: (origin_path: string) => string;
128
+ /**
129
+ * Derive the exported spec identifier for a method. Method names that aren't
130
+ * legal JS identifiers — e.g. the `/` in the `peer/ping` protocol action — have
131
+ * each run of illegal characters collapsed to a single `_`, so `peer/ping`
132
+ * resolves to `peer_ping_action_spec` (the export in `actions/peer_ping.ts`).
133
+ * Already-valid names pass through unchanged.
134
+ */
128
135
  export declare const to_action_spec_identifier: (method: string) => string;
129
136
  export declare const to_action_spec_input_identifier: (method: string) => string;
130
137
  export declare const to_action_spec_output_identifier: (method: string) => string;
138
+ /**
139
+ * Render a method name as an object/interface property key — bare when it's a
140
+ * valid JS identifier, single-quoted otherwise. Method names like `peer/ping`
141
+ * aren't legal as bare keys, so quoting keeps the emitted `ActionSpecs` /
142
+ * `ActionInputs` / `FrontendActionsApi` members valid TypeScript. Pairs with
143
+ * the bracketed indexed-access form (`ActionInputs['peer/ping']`) used for
144
+ * value/type lookups, which already accepts the raw method string.
145
+ */
146
+ export declare const to_action_property_key: (method: string) => string;
131
147
  /**
132
148
  * Generates one method line of the typed `FrontendActionsApi` interface for a
133
149
  * single spec. Encapsulates the input/options/return-type signature shape so
@@ -1 +1 @@
1
- {"version":3,"file":"action_codegen.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_codegen.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"action_codegen.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_codegen.ts"],"names":[],"mappings":"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"}
@@ -296,14 +296,30 @@ export const generate_phase_handlers = (spec, executor, imports, options) => {
296
296
  ) => ${return_type}`;
297
297
  })
298
298
  .join(';\n\t\t');
299
- return `${method}?: {\n\t\t${phase_handlers};\n\t}`;
299
+ return `${to_action_property_key(method)}?: {\n\t\t${phase_handlers};\n\t}`;
300
300
  };
301
301
  /** "DO NOT EDIT" banner naming the gen producer. */
302
302
  export const create_banner = (origin_path) => `generated by ${origin_path} - DO NOT EDIT OR RISK LOST DATA`;
303
303
  // TODO rethink these, see also zzz `codegen.ts`
304
- export const to_action_spec_identifier = (method) => `${method}_action_spec`;
304
+ /**
305
+ * Derive the exported spec identifier for a method. Method names that aren't
306
+ * legal JS identifiers — e.g. the `/` in the `peer/ping` protocol action — have
307
+ * each run of illegal characters collapsed to a single `_`, so `peer/ping`
308
+ * resolves to `peer_ping_action_spec` (the export in `actions/peer_ping.ts`).
309
+ * Already-valid names pass through unchanged.
310
+ */
311
+ export const to_action_spec_identifier = (method) => `${method.replace(/[^A-Za-z0-9_$]+/g, '_')}_action_spec`;
305
312
  export const to_action_spec_input_identifier = (method) => `${to_action_spec_identifier(method)}.input`;
306
313
  export const to_action_spec_output_identifier = (method) => `${to_action_spec_identifier(method)}.output`;
314
+ /**
315
+ * Render a method name as an object/interface property key — bare when it's a
316
+ * valid JS identifier, single-quoted otherwise. Method names like `peer/ping`
317
+ * aren't legal as bare keys, so quoting keeps the emitted `ActionSpecs` /
318
+ * `ActionInputs` / `FrontendActionsApi` members valid TypeScript. Pairs with
319
+ * the bracketed indexed-access form (`ActionInputs['peer/ping']`) used for
320
+ * value/type lookups, which already accepts the raw method string.
321
+ */
322
+ export const to_action_property_key = (method) => /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(method) ? method : `'${method}'`;
307
323
  /**
308
324
  * Generates one method line of the typed `FrontendActionsApi` interface for a
309
325
  * single spec. Encapsulates the input/options/return-type signature shape so
@@ -379,7 +395,7 @@ export const generate_actions_api_method_signature = (spec, imports, options) =>
379
395
  imports.add_type('@fuzdev/fuz_util/result.ts', 'Result');
380
396
  imports.add_type('@fuzdev/fuz_app/http/jsonrpc.ts', 'JsonrpcErrorObject');
381
397
  }
382
- return `${spec.method}: (${input_param}${options_param}) => ${return_type};`;
398
+ return `${to_action_property_key(spec.method)}: (${input_param}${options_param}) => ${return_type};`;
383
399
  };
384
400
  // --------------------------------------------------------------------------
385
401
  // High-level codegen helpers — compose the lower-level primitives above into
@@ -456,7 +472,7 @@ export const resolve_spec_qualifier = (imports, options) => {
456
472
  return options.qualify_spec;
457
473
  const specs_module = options?.specs_module ?? DEFAULT_SPECS_MODULE;
458
474
  imports.add(specs_module, '* as specs');
459
- return (s) => `specs.${s.method}_action_spec`;
475
+ return (s) => `specs.${to_action_spec_identifier(s.method)}`;
460
476
  };
461
477
  /**
462
478
  * Emit one or more `z.enum([...])` declarations for action method names —
@@ -592,8 +608,12 @@ export interface ActionSpecs {}
592
608
  export const action_specs: Array<ActionSpecUnion> = Object.values(ActionSpecs);`;
593
609
  }
594
610
  const qualify = resolve_spec_qualifier(imports, options);
595
- const value_lines = filtered.map((s) => `\t${s.method}: ${qualify(s)},`).join('\n');
596
- const type_lines = filtered.map((s) => `\t${s.method}: typeof ${qualify(s)};`).join('\n');
611
+ const value_lines = filtered
612
+ .map((s) => `\t${to_action_property_key(s.method)}: ${qualify(s)},`)
613
+ .join('\n');
614
+ const type_lines = filtered
615
+ .map((s) => `\t${to_action_property_key(s.method)}: typeof ${qualify(s)};`)
616
+ .join('\n');
597
617
  return `/**
598
618
  * Action specifications indexed by method name.
599
619
  * These represent the complete action spec definitions.
@@ -643,13 +663,17 @@ export interface ActionOutputs {}`;
643
663
  }
644
664
  imports.add('zod', 'z');
645
665
  const qualify = resolve_spec_qualifier(imports, options);
646
- const inputs_value = filtered.map((s) => `\t${s.method}: ${qualify(s)}.input,`).join('\n');
666
+ const inputs_value = filtered
667
+ .map((s) => `\t${to_action_property_key(s.method)}: ${qualify(s)}.input,`)
668
+ .join('\n');
647
669
  const inputs_type = filtered
648
- .map((s) => `\t${s.method}: z.infer<typeof ${qualify(s)}.input>;`)
670
+ .map((s) => `\t${to_action_property_key(s.method)}: z.infer<typeof ${qualify(s)}.input>;`)
671
+ .join('\n');
672
+ const outputs_value = filtered
673
+ .map((s) => `\t${to_action_property_key(s.method)}: ${qualify(s)}.output,`)
649
674
  .join('\n');
650
- const outputs_value = filtered.map((s) => `\t${s.method}: ${qualify(s)}.output,`).join('\n');
651
675
  const outputs_type = filtered
652
- .map((s) => `\t${s.method}: z.infer<typeof ${qualify(s)}.output>;`)
676
+ .map((s) => `\t${to_action_property_key(s.method)}: z.infer<typeof ${qualify(s)}.output>;`)
653
677
  .join('\n');
654
678
  return `/**
655
679
  * Action parameter schemas indexed by method name.
@@ -722,7 +746,7 @@ export interface ActionEventDatas {}`;
722
746
  const type_args = spec.kind === 'remote_notification'
723
747
  ? `<'${spec.method}', ActionInputs['${spec.method}']>`
724
748
  : `<'${spec.method}', ActionInputs['${spec.method}'], ActionOutputs['${spec.method}']>`;
725
- return `\t${spec.method}: ${data_type}${type_args};`;
749
+ return `\t${to_action_property_key(spec.method)}: ${data_type}${type_args};`;
726
750
  });
727
751
  return `/**
728
752
  * Action event data types indexed by method name.
@@ -873,7 +897,7 @@ export const broadcast_action_specs: ReadonlyArray<ActionSpecUnion> = [];`;
873
897
  const qualify = resolve_spec_qualifier(imports, options);
874
898
  const interface_body = '\n' +
875
899
  broadcast
876
- .map((s) => `\t${s.method}: (input: ActionInputs['${s.method}']) => Promise<void>;`)
900
+ .map((s) => `\t${to_action_property_key(s.method)}: (input: ActionInputs['${s.method}']) => Promise<void>;`)
877
901
  .join('\n') +
878
902
  '\n';
879
903
  const array_body = '\n' + broadcast.map((s) => `\t${qualify(s)},`).join('\n') + '\n';
@@ -979,7 +1003,7 @@ export const create_namespace_qualifier = (sources, imports) => {
979
1003
  if (!ns) {
980
1004
  throw new Error(`unknown action method passed to qualify_spec: ${spec.method} — not in any registered source`);
981
1005
  }
982
- return `${ns}.${spec.method}_action_spec`;
1006
+ return `${ns}.${to_action_spec_identifier(spec.method)}`;
983
1007
  };
984
1008
  return { qualify_spec, all_specs };
985
1009
  };
package/dist/db/CLAUDE.md CHANGED
@@ -128,14 +128,16 @@ DO NOTHING`), `_put_fact_refs`, `_get_fact` / `_get_fact_meta` / `_has_fact`
128
128
 
129
129
  FK dependency dictates order; consumers register via `migration_namespaces`
130
130
  on `create_app_backend` (after the built-in `fuz_auth` namespace). The fact
131
- namespace is independent (no FK to cell) but conventionally sits between cell
132
- and cell_history:
131
+ namespace is FK-independent so its slot is free; the spine binary and every
132
+ consumer place it last, keeping cell + its `cell_history` FK-child adjacent
133
+ (cross-namespace order is immaterial to the `schema_version` rows — `sequence`
134
+ is assigned per-namespace — so only the cell→cell_history FK constrains it):
133
135
 
134
136
  ```
135
137
  auth_migration_ns (built-in, fuz_auth)
136
- → CELL_MIGRATION_NS (fuz_cell — FKs actor.id)
137
- → FACT_MIGRATION_NS (fuz_facts — no external FK; optional)
138
+ → CELL_MIGRATION_NS (fuz_cell — FKs actor.id)
138
139
  → CELL_HISTORY_MIGRATION_NS (fuz_cell_history — FKs cell.id)
140
+ → FACT_MIGRATION_NS (fuz_facts — no external FK; slot is free)
139
141
  ```
140
142
 
141
143
  ### Pre-stable migration policy
@@ -27,9 +27,10 @@
27
27
  * `_at`-everywhere convention used by `account`, `actor`, `audit_log`,
28
28
  * `role_grant`, etc.
29
29
  *
30
- * **Single-migration shape**: `cell_v0` creates the canonical
30
+ * **Single-migration shape**: `full_cell_schema` creates the canonical
31
31
  * cell + cell_grant + cell_field + cell_item layout in one shot from the
32
- * live exported constants.
32
+ * live exported constants. The dormant `cell_history` table lives in the
33
+ * separate `fuz_cell_history` namespace (`cell_history_ddl.ts`).
33
34
  *
34
35
  * @module
35
36
  */
@@ -1 +1 @@
1
- {"version":3,"file":"cell_ddl.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/db/cell_ddl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAGH,OAAO,KAAK,EAAC,SAAS,EAAE,kBAAkB,EAAC,MAAM,cAAc,CAAC;AAEhE;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,oBAAoB,oIAI1B,CAAC;AAER;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,WAAW,4aAYtB,CAAC;AAEH;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,MAAM,CAYtC,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,0iBAc5B,CAAC;AAEH;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,MAAM,CAW5C,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,+RAO5B,CAAC;AAEH;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,MAAM,CAE5C,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,qSAO3B,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC,MAAM,CAG3C,CAAC;AAEF,6EAA6E;AAC7E,eAAO,MAAM,gBAAgB,4DAA6D,CAAC;AAE3F,uBAAuB;AACvB,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,SAAS,CAuB5C,CAAC;AAEF,gDAAgD;AAChD,eAAO,MAAM,wBAAwB,aAAa,CAAC;AAEnD,wDAAwD;AACxD,eAAO,MAAM,iBAAiB,EAAE,kBAG/B,CAAC"}
1
+ {"version":3,"file":"cell_ddl.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/db/cell_ddl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAGH,OAAO,KAAK,EAAC,SAAS,EAAE,kBAAkB,EAAC,MAAM,cAAc,CAAC;AAEhE;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,oBAAoB,oIAI1B,CAAC;AAER;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,WAAW,4aAYtB,CAAC;AAEH;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,MAAM,CAYtC,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,0iBAc5B,CAAC;AAEH;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,MAAM,CAW5C,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,+RAO5B,CAAC;AAEH;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,MAAM,CAE5C,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,qSAO3B,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC,MAAM,CAG3C,CAAC;AAEF,6EAA6E;AAC7E,eAAO,MAAM,gBAAgB,4DAA6D,CAAC;AAE3F,uBAAuB;AACvB,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,SAAS,CAuB5C,CAAC;AAEF,gDAAgD;AAChD,eAAO,MAAM,wBAAwB,aAAa,CAAC;AAEnD,wDAAwD;AACxD,eAAO,MAAM,iBAAiB,EAAE,kBAG/B,CAAC"}
@@ -27,9 +27,10 @@
27
27
  * `_at`-everywhere convention used by `account`, `actor`, `audit_log`,
28
28
  * `role_grant`, etc.
29
29
  *
30
- * **Single-migration shape**: `cell_v0` creates the canonical
30
+ * **Single-migration shape**: `full_cell_schema` creates the canonical
31
31
  * cell + cell_grant + cell_field + cell_item layout in one shot from the
32
- * live exported constants.
32
+ * live exported constants. The dormant `cell_history` table lives in the
33
+ * separate `fuz_cell_history` namespace (`cell_history_ddl.ts`).
33
34
  *
34
35
  * @module
35
36
  */
@@ -216,7 +217,7 @@ export const CELL_DROP_TABLES = ['cell_field', 'cell_item', 'cell_grant', 'cell'
216
217
  /** Cell migrations. */
217
218
  export const CELL_MIGRATIONS = [
218
219
  {
219
- name: 'cell_v0',
220
+ name: 'full_cell_schema',
220
221
  up: async (db) => {
221
222
  await db.query(CELL_VISIBILITY_TYPE);
222
223
  await db.query(CELL_SCHEMA);
@@ -43,7 +43,7 @@ export const CELL_HISTORY_DROP_TABLES = ['cell_history'];
43
43
  /** Cell-history migrations. */
44
44
  export const CELL_HISTORY_MIGRATIONS = [
45
45
  {
46
- name: 'cell_history_v0',
46
+ name: 'full_cell_history_schema',
47
47
  up: async (db) => {
48
48
  await db.query(CELL_HISTORY_SCHEMA);
49
49
  for (const sql of CELL_HISTORY_INDEXES) {
@@ -53,7 +53,7 @@ export const FACT_DROP_TABLES = ['memo', 'fact_ref', 'fact'];
53
53
  /** Fact + memo migrations. */
54
54
  export const FACT_MIGRATIONS = [
55
55
  {
56
- name: 'facts_v0',
56
+ name: 'full_fact_schema',
57
57
  up: async (db) => {
58
58
  await db.query(FACTS_SCHEMA);
59
59
  await db.query(FACT_REFS_SCHEMA);
@@ -6,6 +6,17 @@
6
6
  * `(namespace, name, sequence, applied_at)` — and the runner verifies the
7
7
  * applied list is a name-prefix of the code's migration array at boot.
8
8
  *
9
+ * **`name` is descriptive identity, not a version ordinal.** The runner orders
10
+ * by the `sequence` column and matches `name` by array position — it never
11
+ * parses the name — so `name` carries *what the migration is*
12
+ * (`full_cell_schema`, `role_grant_offer_and_scoped_role_grants`), and the
13
+ * redundant `_vN` ordinal is avoided (it would only duplicate `sequence`, and
14
+ * a `cell_v0` name tempts editing "v0" in place). `name` is half the
15
+ * `schema_version` PK (with `namespace`), so a rename is an identity change
16
+ * every already-migrated DB sees as `name-divergence-at-N`. This is also the
17
+ * cross-impl contract: the TS and Rust spines must record byte-identical
18
+ * `(namespace, name, sequence)` so a consumer can swap backends over one DB.
19
+ *
9
20
  * **Schema is not stabilized yet — append-only is NOT the rule.** While
10
21
  * fuz_app is pre-stable, migration bodies, names, and positions can change
11
22
  * freely between versions; consumers upgrading across a schema change are
@@ -1 +1 @@
1
- {"version":3,"file":"migrate.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/db/migrate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAIH,OAAO,KAAK,EAAC,EAAE,EAAC,MAAM,SAAS,CAAC;AAEhC;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;CAC7B;AAED,2DAA2D;AAC3D,MAAM,WAAW,eAAe;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,+EAA+E;IAC/E,aAAa,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;CAC7B;AAED;;;;;GAKG;AACH,MAAM,MAAM,kBAAkB,GAC3B,sBAAsB,GACtB,sBAAsB,GACtB,mBAAmB,GACnB,kBAAkB,GAClB,2BAA2B,GAC3B,4BAA4B,GAC5B,sCAAsC,CAAC;AAE1C,8DAA8D;AAC9D,MAAM,WAAW,qBAAqB;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACtC,KAAK,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;;;GAIG;AACH,qBAAa,cAAe,SAAQ,KAAK;IACxC,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC;IAClC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;gBAEnC,IAAI,EAAE,kBAAkB,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB;CAQtF;AA6ED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,cAAc,GAC1B,IAAI,EAAE,EACN,YAAY,KAAK,CAAC,kBAAkB,CAAC,KACnC,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC,CAuFhC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,eAAO,MAAM,QAAQ,GACpB,IAAI,EAAE,EACN,IAAI,kBAAkB,EACtB,OAAO,aAAa,CAAC,MAAM,CAAC,KAC1B,OAAO,CAAC,IAAI,CA+Dd,CAAC"}
1
+ {"version":3,"file":"migrate.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/db/migrate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AAIH,OAAO,KAAK,EAAC,EAAE,EAAC,MAAM,SAAS,CAAC;AAEhC;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;CAC7B;AAED,2DAA2D;AAC3D,MAAM,WAAW,eAAe;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,+EAA+E;IAC/E,aAAa,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;CAC7B;AAED;;;;;GAKG;AACH,MAAM,MAAM,kBAAkB,GAC3B,sBAAsB,GACtB,sBAAsB,GACtB,mBAAmB,GACnB,kBAAkB,GAClB,2BAA2B,GAC3B,4BAA4B,GAC5B,sCAAsC,CAAC;AAE1C,8DAA8D;AAC9D,MAAM,WAAW,qBAAqB;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACtC,KAAK,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;;;GAIG;AACH,qBAAa,cAAe,SAAQ,KAAK;IACxC,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC;IAClC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;gBAEnC,IAAI,EAAE,kBAAkB,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB;CAQtF;AA6ED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,cAAc,GAC1B,IAAI,EAAE,EACN,YAAY,KAAK,CAAC,kBAAkB,CAAC,KACnC,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC,CAuFhC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,eAAO,MAAM,QAAQ,GACpB,IAAI,EAAE,EACN,IAAI,kBAAkB,EACtB,OAAO,aAAa,CAAC,MAAM,CAAC,KAC1B,OAAO,CAAC,IAAI,CA+Dd,CAAC"}
@@ -6,6 +6,17 @@
6
6
  * `(namespace, name, sequence, applied_at)` — and the runner verifies the
7
7
  * applied list is a name-prefix of the code's migration array at boot.
8
8
  *
9
+ * **`name` is descriptive identity, not a version ordinal.** The runner orders
10
+ * by the `sequence` column and matches `name` by array position — it never
11
+ * parses the name — so `name` carries *what the migration is*
12
+ * (`full_cell_schema`, `role_grant_offer_and_scoped_role_grants`), and the
13
+ * redundant `_vN` ordinal is avoided (it would only duplicate `sequence`, and
14
+ * a `cell_v0` name tempts editing "v0" in place). `name` is half the
15
+ * `schema_version` PK (with `namespace`), so a rename is an identity change
16
+ * every already-migrated DB sees as `name-divergence-at-N`. This is also the
17
+ * cross-impl contract: the TS and Rust spines must record byte-identical
18
+ * `(namespace, name, sequence)` so a consumer can swap backends over one DB.
19
+ *
9
20
  * **Schema is not stabilized yet — append-only is NOT the rule.** While
10
21
  * fuz_app is pre-stable, migration bodies, names, and positions can change
11
22
  * freely between versions; consumers upgrading across a schema change are
@@ -214,6 +214,7 @@ test-only by construction.
214
214
 
215
215
  - `query_schema_snapshot(db, options?)` — introspects a live DB into a deterministic `SchemaSnapshot` via `pg_catalog` + `information_schema`. Captures tables, columns (with `udt_name` to distinguish int4/int8), indexes (`indexdef`), constraints (`pg_get_constraintdef`), sequences, and enum types (`pg_enum` labels in declared `enumsortorder`, so a `cell_visibility` label-set/order drift is gated). The `schema_version` migration tracker is always excluded — it's framework bookkeeping, not domain schema, and impls organize migration namespaces differently. Twinned by `fuz_db::query_schema_snapshot` (Rust); the `_testing_schema_snapshot` RPC's wire validator is the shared `SchemaSnapshot`, so the enum field must serialize on both sides.
216
216
  - `SchemaSnapshot` — the Zod schema is canonical (co-located in `schema_introspect.ts`; the cross-impl `_testing_schema_snapshot` RPC action reuses it as its wire validator, and the type is `z.infer`'d from it). Fully JSON-serializable; every collection deterministically sorted on capture so structural equality is stable across runs.
217
+ - `query_migration_tracker(db)` / `MigrationTracker` — the migration-_identity_ twin of the snapshot: reads the `schema_version` tracker rows (`[{namespace, name, sequence}]`) the snapshot deliberately _excludes_. `MigrationTracker` is the `_testing_migration_tracker` RPC's wire validator; pairs with `assert_migration_trackers_equal` to gate that the two spines record byte-identical migration identity (the swap-freely invariant), catching a migration-name or namespace-partitioning drift the provenance-agnostic schema snapshot can't see.
217
218
 
218
219
  ### `schema_parity.ts` — `assert_schema_snapshots_equal`
219
220
 
@@ -221,6 +222,7 @@ test-only by construction.
221
222
  - `format_schema_diffs(diffs, labels?)` — human-readable multi-line rendering; labels name the impl on each side (e.g., `{a: 'deno', b: 'rust'}`).
222
223
  - `assert_schema_snapshots_equal(a, b, labels?)` — throws on drift with a fully-formatted diff message.
223
224
  - `SchemaDiff` — tagged-union per drift kind: `table_only_in`, `column_only_in`, `column_field_differs`, `index_only_in`, `index_definition_differs`, `constraint_only_in`, `constraint_differs`, `sequence_only_in`, `sequence_data_type_differs`, `enum_only_in`, `enum_labels_differ` (enum labels compared positionally — declared order is significant).
225
+ - `diff_migration_trackers(a, b)` / `format_migration_tracker_diffs(diffs, labels?)` / `assert_migration_trackers_equal(a, b, labels?)` — the migration-identity twins of the snapshot diff/format/assert, over two `MigrationTracker`s. `MigrationTrackerDiff` is keyed on `(namespace, name)` (the `schema_version` PK): `tracker_row_only_in` (a migration rename or namespace re-partition) and `tracker_sequence_differs` (a re-order).
224
226
 
225
227
  fuz_app's own spine gates this cross-process via the `cross_backend_parity` project (`schema_parity.cross.test.ts` + the dual-spawn `global_setup_schema_parity.ts`), diffing the TS spine ↔ `testing_spine_stub` full schema — `npm run test:cross:parity`. The forge has its own deno↔rust parity gate.
226
228
 
@@ -3,7 +3,7 @@ import { Uuid } from '@fuzdev/fuz_util/id.ts';
3
3
  import type { TestAccount } from '../app_server.js';
4
4
  import type { BackendCapabilities } from './capabilities.js';
5
5
  import { type FetchTransport } from '../transports/fetch_transport.js';
6
- import type { SchemaSnapshot } from '../schema_introspect.js';
6
+ import { MigrationTracker, type SchemaSnapshot } from '../schema_introspect.js';
7
7
  import { ActionManifest } from './action_manifest.js';
8
8
  import type { BackendHandle } from './spawn_backend.js';
9
9
  /**
@@ -406,6 +406,18 @@ export declare const capture_schema_snapshot: (handle: ReconstructedBootstrapped
406
406
  * `fuz_testing` mirror); the normalized shapes match by design.
407
407
  */
408
408
  export declare const capture_action_manifest: (handle: ReconstructedBootstrappedBackendHandle) => Promise<ActionManifest>;
409
+ /**
410
+ * Capture a backend's `schema_version` migration tracker over the
411
+ * `_testing_migration_tracker` RPC action (keeper daemon-token channel). The
412
+ * provenance twin of `capture_schema_snapshot` — where that reads the
413
+ * resulting schema (and excludes the tracker), this reads the tracker rows
414
+ * themselves. Pair two calls with `assert_migration_trackers_equal`
415
+ * (`testing/schema_parity.ts`) to gate that the TS spine and the Rust
416
+ * `testing_spine_stub` record byte-identical migration identity
417
+ * (`namespace` + `name` + `sequence`) — the invariant the schema-snapshot
418
+ * gate is blind to.
419
+ */
420
+ export declare const capture_migration_tracker: (handle: ReconstructedBootstrappedBackendHandle) => Promise<MigrationTracker>;
409
421
  /**
410
422
  * Backdating offset (seconds) the `mint_expired_session` seam passes to
411
423
  * `mint_test_session` / `_testing_mint_session`. A minute in the past is
@@ -1 +1 @@
1
- {"version":3,"file":"setup.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/setup.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/setup.ts"],"names":[],"mappings":"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"}
@@ -27,6 +27,7 @@ import { DAEMON_TOKEN_HEADER } from '../../auth/daemon_token.js';
27
27
  import { USERNAME_LENGTH_MAX } from '../../primitive_schemas.js';
28
28
  import { DEFAULT_TEST_PASSWORD } from '../test_credentials.js';
29
29
  import { create_fetch_transport } from '../transports/fetch_transport.js';
30
+ import { MigrationTracker } from '../schema_introspect.js';
30
31
  import { ActionManifest } from './action_manifest.js';
31
32
  /**
32
33
  * Build an `ExtraAccountFixture` from a seeded `{account, actor,
@@ -179,6 +180,22 @@ export const capture_schema_snapshot = async (handle, options = {}) => {
179
180
  // reconcile first, so it's left as a follow-up.
180
181
  return raw;
181
182
  };
183
+ /**
184
+ * Capture a no-arg daemon-token introspection RPC and validate the wire
185
+ * response against `schema`. The shared shape behind the parse-based
186
+ * `capture_*` cross-impl parity probes: call a `_testing_*` introspection
187
+ * action over the keeper's daemon-token channel, then `parse` so a shape
188
+ * drift between the TS and Rust answers fails loud at the boundary.
189
+ *
190
+ * (`capture_schema_snapshot` deliberately stays separate: it *casts* rather
191
+ * than parses — narrowing a large snapshot to the Zod model would silently
192
+ * drop unmodeled fields the parity diff should still see — and it takes an
193
+ * `exclude_tables` param.)
194
+ */
195
+ const capture_via_daemon = async (handle, method, schema) => {
196
+ const raw = await rpc_via_transport(handle.keeper_daemon_transport, handle.config.rpc_path, method, {}, handle.config.name, { [DAEMON_TOKEN_HEADER]: handle.daemon_token });
197
+ return schema.parse(raw);
198
+ };
182
199
  /**
183
200
  * Capture a backend's live RPC action manifest over the
184
201
  * `_testing_action_manifest` RPC action (keeper daemon-token channel). The
@@ -189,10 +206,19 @@ export const capture_schema_snapshot = async (handle, options = {}) => {
189
206
  * own live registry (TS via `build_action_manifest`, Rust via the
190
207
  * `fuz_testing` mirror); the normalized shapes match by design.
191
208
  */
192
- export const capture_action_manifest = async (handle) => {
193
- const raw = await rpc_via_transport(handle.keeper_daemon_transport, handle.config.rpc_path, '_testing_action_manifest', {}, handle.config.name, { [DAEMON_TOKEN_HEADER]: handle.daemon_token });
194
- return ActionManifest.parse(raw);
195
- };
209
+ export const capture_action_manifest = async (handle) => capture_via_daemon(handle, '_testing_action_manifest', ActionManifest);
210
+ /**
211
+ * Capture a backend's `schema_version` migration tracker over the
212
+ * `_testing_migration_tracker` RPC action (keeper daemon-token channel). The
213
+ * provenance twin of `capture_schema_snapshot` — where that reads the
214
+ * resulting schema (and excludes the tracker), this reads the tracker rows
215
+ * themselves. Pair two calls with `assert_migration_trackers_equal`
216
+ * (`testing/schema_parity.ts`) to gate that the TS spine and the Rust
217
+ * `testing_spine_stub` record byte-identical migration identity
218
+ * (`namespace` + `name` + `sequence`) — the invariant the schema-snapshot
219
+ * gate is blind to.
220
+ */
221
+ export const capture_migration_tracker = async (handle) => capture_via_daemon(handle, '_testing_migration_tracker', MigrationTracker);
196
222
  /**
197
223
  * Backdating offset (seconds) the `mint_expired_session` seam passes to
198
224
  * `mint_test_session` / `_testing_mint_session`. A minute in the past is
@@ -1 +1 @@
1
- {"version":3,"file":"testing_backdoor.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/testing_backdoor.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA0D9B,OAAO,KAAK,EAAC,wBAAwB,EAAc,MAAM,YAAY,CAAC;AAkEtE,kEAAkE;AAClE,MAAM,MAAM,+BAA+B,GAAG,wBAAwB,CAAC;AAEvE,eAAO,MAAM,qCAAqC,GACjD,SAAS,+BAA+B,KACtC,IAiCF,CAAC"}
1
+ {"version":3,"file":"testing_backdoor.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/testing_backdoor.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA2D9B,OAAO,KAAK,EAAC,wBAAwB,EAAc,MAAM,YAAY,CAAC;AAqEtE,kEAAkE;AAClE,MAAM,MAAM,+BAA+B,GAAG,wBAAwB,CAAC;AAEvE,eAAO,MAAM,qCAAqC,GACjD,SAAS,+BAA+B,KACtC,IAiCF,CAAC"}
@@ -4,10 +4,11 @@ import '../assert_dev_env.js';
4
4
  * actions.
5
5
  *
6
6
  * `_testing_reset` / `_testing_mint_session` / `_testing_put_fact` /
7
- * `_testing_schema_snapshot` / `_testing_action_manifest` are privileged
8
- * test-binary actions the production wire never exposes — three direct DB
9
- * writes (full auth wipe, forged session row, raw fact insert) plus two
10
- * introspection reads (the live schema + the live RPC registry, the highest
7
+ * `_testing_schema_snapshot` / `_testing_migration_tracker` /
8
+ * `_testing_action_manifest` are privileged test-binary actions the production
9
+ * wire never exposes — three direct DB writes (full auth wipe, forged session
10
+ * row, raw fact insert) plus three introspection reads (the live schema, the
11
+ * `schema_version` migration tracker, and the live RPC registry — the highest
11
12
  * info-leak of the set were the gate to break). Their only structural fence
12
13
  * is the **daemon-token** credential gate on
13
14
  * each spec's `auth` axis. A test binary live-mounts them on its RPC
@@ -67,6 +68,9 @@ const backdoor_methods = [
67
68
  // The schema-dump read — `exclude_tables` is optional, so `{}` is valid
68
69
  // and clears the 400 phase like the writes above.
69
70
  { method: '_testing_schema_snapshot', params: {} },
71
+ // The migration-tracker-dump read — input is an empty strict object, so `{}`
72
+ // is valid and clears the 400 phase, reaching the credential gate like the rest.
73
+ { method: '_testing_migration_tracker', params: {} },
70
74
  // The RPC-registry-dump read — input is an empty strict object, so `{}` is
71
75
  // valid and clears the 400 phase, reaching the credential gate like the rest.
72
76
  { method: '_testing_action_manifest', params: {} },
@@ -2,15 +2,18 @@ import '../assert_dev_env.js';
2
2
  /**
3
3
  * Test-binary RPC actions for cross-process integration tests.
4
4
  *
5
- * Five daemon-token-authed actions, bundled by `create_testing_actions`:
5
+ * Six daemon-token-authed actions, bundled by `create_testing_actions`:
6
6
  * **`_testing_reset`** (DB wipe + keeper re-seed), **`_testing_drain_effects`**
7
7
  * (audit barrier), **`_testing_mint_session`** (forge an
8
8
  * expired-by-construction server-side session for the expiry conformance
9
9
  * cases), **`_testing_put_fact`** (seed an embedded fact for the fact-serving
10
- * suite), and **`_testing_schema_snapshot`** (introspect the live schema for
11
- * cross-impl parity diffing against a Rust backend's `fuz_db` snapshot).
10
+ * suite), **`_testing_schema_snapshot`** (introspect the live schema for
11
+ * cross-impl parity diffing against a Rust backend's `fuz_db` snapshot), and
12
+ * **`_testing_migration_tracker`** (dump the `schema_version` tracker rows for
13
+ * cross-impl migration-identity parity — the provenance half the snapshot gate
14
+ * excludes by design).
12
15
  *
13
- * A sixth daemon-token action, **`_testing_action_manifest`** (dump the live
16
+ * A further daemon-token action, **`_testing_action_manifest`** (dump the live
14
17
  * RPC registry for cross-impl method-set + auth-shape parity), lives here too
15
18
  * but is **not** bundled by `create_testing_actions` — it must enumerate
16
19
  * *every* mounted method, so it's appended at the full-mount layer
@@ -336,6 +339,47 @@ export declare const testing_schema_snapshot_action_spec: {
336
339
  * `create_testing_actions`; mount directly for in-process use.
337
340
  */
338
341
  export declare const create_testing_schema_snapshot_action: () => RpcAction;
342
+ /**
343
+ * `_testing_migration_tracker` — dump the `schema_version` tracker rows as a
344
+ * normalized `MigrationTracker` (`[{namespace, name, sequence}]`) for
345
+ * cross-impl migration-identity diffing. The provenance half of
346
+ * `_testing_schema_snapshot`: where that captures the resulting *schema*
347
+ * (and excludes the tracker by design), this captures the tracker *itself*,
348
+ * so the cross-backend harness can assert the two spines record byte-identical
349
+ * migration identity. This closes the gap that let the cell/fact
350
+ * migration-name divergence reach the visiones cutover undetected
351
+ * (`name-divergence-at-N` — same schema, divergent recorded names).
352
+ *
353
+ * `auth` gates on the daemon-token credential, matching `_testing_reset`. The
354
+ * Rust mirror is `fuz_testing::create_testing_migration_tracker_action_spec`.
355
+ */
356
+ export declare const testing_migration_tracker_action_spec: {
357
+ readonly method: "_testing_migration_tracker";
358
+ readonly kind: "request_response";
359
+ readonly initiator: "frontend";
360
+ readonly auth: {
361
+ readonly account: "required";
362
+ readonly actor: "none";
363
+ readonly credential_types: readonly ["daemon_token"];
364
+ };
365
+ readonly side_effects: false;
366
+ readonly input: z.ZodObject<{}, z.core.$strict>;
367
+ readonly output: z.ZodObject<{
368
+ entries: z.ZodArray<z.ZodObject<{
369
+ namespace: z.ZodString;
370
+ name: z.ZodString;
371
+ sequence: z.ZodNumber;
372
+ }, z.core.$strip>>;
373
+ }, z.core.$strip>;
374
+ readonly async: true;
375
+ readonly description: string;
376
+ };
377
+ /**
378
+ * Build the standalone `_testing_migration_tracker` action. No deps — reads
379
+ * `ctx.db`'s `schema_version` via `query_migration_tracker`. Bundled by
380
+ * `create_testing_actions`; mount directly for in-process use.
381
+ */
382
+ export declare const create_testing_migration_tracker_action: () => RpcAction;
339
383
  /**
340
384
  * `_testing_action_manifest` — dump the backend's live RPC method set as a
341
385
  * normalized `ActionManifest` (one entry per method: `{method, side_effects,
@@ -1 +1 @@
1
- {"version":3,"file":"testing_reset_actions.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/testing_reset_actions.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiEG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAItB,OAAO,EAAa,KAAK,SAAS,EAAC,MAAM,6BAA6B,CAAC;AAKvE,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,oBAAoB,CAAC;AAChD,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,8BAA8B,CAAC;AACjE,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,4BAA4B,CAAC;AACjE,OAAO,KAAK,EAAC,EAAE,EAAC,MAAM,gBAAgB,CAAC;AAgCvC;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;QAiBpC;;;;;;;;WAQG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAWyC,CAAC;AAE/C;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,iCAAiC;;;;;;;;;;;;;;;;CAWA,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;CAwBC,CAAC;AAE/C;;;;;;GAMG;AACH,eAAO,MAAM,mCAAmC,QAAO,SACiB,CAAC;AAEzE;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;;;;CAeK,CAAC;AAE/C;;;;;;;;;GASG;AACH,eAAO,MAAM,mCAAmC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAWF,CAAC;AAE/C;;;;GAIG;AACH,eAAO,MAAM,qCAAqC,QAAO,SAGvD,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,mCAAmC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAYF,CAAC;AAyB/C,eAAO,MAAM,qCAAqC,GACjD,SAAS,aAAa,CAAC,SAAS,CAAC,KAC/B,SAMF,CAAC;AAEF,4CAA4C;AAC5C,MAAM,WAAW,2BAA2B;IAC3C;;;;;OAKG;IACH,QAAQ,CAAC,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACjD;;;;;OAKG;IACH,QAAQ,CAAC,kBAAkB,EAAE,gBAAgB,CAAC;IAC9C;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACxD;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,sBAAsB,GAClC,MAAM,OAAO,EACb,SAAS,2BAA2B,KAClC,KAAK,CAAC,SAAS,CAqIjB,CAAC;AAEF,0FAA0F;AAC1F,eAAO,MAAM,0BAA0B,UAAmC,CAAC"}
1
+ {"version":3,"file":"testing_reset_actions.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/testing_reset_actions.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoEG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAItB,OAAO,EAAa,KAAK,SAAS,EAAC,MAAM,6BAA6B,CAAC;AAKvE,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,oBAAoB,CAAC;AAChD,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,8BAA8B,CAAC;AACjE,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,4BAA4B,CAAC;AACjE,OAAO,KAAK,EAAC,EAAE,EAAC,MAAM,gBAAgB,CAAC;AAqCvC;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;QAiBpC;;;;;;;;WAQG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAWyC,CAAC;AAE/C;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,iCAAiC;;;;;;;;;;;;;;;;CAWA,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;CAwBC,CAAC;AAE/C;;;;;;GAMG;AACH,eAAO,MAAM,mCAAmC,QAAO,SACiB,CAAC;AAEzE;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;;;;CAeK,CAAC;AAE/C;;;;;;;;;GASG;AACH,eAAO,MAAM,mCAAmC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAWF,CAAC;AAE/C;;;;GAIG;AACH,eAAO,MAAM,qCAAqC,QAAO,SAGvD,CAAC;AAEH;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,qCAAqC;;;;;;;;;;;;;;;;;;;;CAYJ,CAAC;AAE/C;;;;GAIG;AACH,eAAO,MAAM,uCAAuC,QAAO,SAGzD,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,mCAAmC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAYF,CAAC;AAyB/C,eAAO,MAAM,qCAAqC,GACjD,SAAS,aAAa,CAAC,SAAS,CAAC,KAC/B,SAMF,CAAC;AAEF,4CAA4C;AAC5C,MAAM,WAAW,2BAA2B;IAC3C;;;;;OAKG;IACH,QAAQ,CAAC,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACjD;;;;;OAKG;IACH,QAAQ,CAAC,kBAAkB,EAAE,gBAAgB,CAAC;IAC9C;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACxD;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,sBAAsB,GAClC,MAAM,OAAO,EACb,SAAS,2BAA2B,KAClC,KAAK,CAAC,SAAS,CAsIjB,CAAC;AAEF,0FAA0F;AAC1F,eAAO,MAAM,0BAA0B,UAAmC,CAAC"}
@@ -2,15 +2,18 @@ import '../assert_dev_env.js';
2
2
  /**
3
3
  * Test-binary RPC actions for cross-process integration tests.
4
4
  *
5
- * Five daemon-token-authed actions, bundled by `create_testing_actions`:
5
+ * Six daemon-token-authed actions, bundled by `create_testing_actions`:
6
6
  * **`_testing_reset`** (DB wipe + keeper re-seed), **`_testing_drain_effects`**
7
7
  * (audit barrier), **`_testing_mint_session`** (forge an
8
8
  * expired-by-construction server-side session for the expiry conformance
9
9
  * cases), **`_testing_put_fact`** (seed an embedded fact for the fact-serving
10
- * suite), and **`_testing_schema_snapshot`** (introspect the live schema for
11
- * cross-impl parity diffing against a Rust backend's `fuz_db` snapshot).
10
+ * suite), **`_testing_schema_snapshot`** (introspect the live schema for
11
+ * cross-impl parity diffing against a Rust backend's `fuz_db` snapshot), and
12
+ * **`_testing_migration_tracker`** (dump the `schema_version` tracker rows for
13
+ * cross-impl migration-identity parity — the provenance half the snapshot gate
14
+ * excludes by design).
12
15
  *
13
- * A sixth daemon-token action, **`_testing_action_manifest`** (dump the live
16
+ * A further daemon-token action, **`_testing_action_manifest`** (dump the live
14
17
  * RPC registry for cross-impl method-set + auth-shape parity), lives here too
15
18
  * but is **not** bundled by `create_testing_actions` — it must enumerate
16
19
  * *every* mounted method, so it's appended at the full-mount layer
@@ -73,7 +76,7 @@ import { protocol_action_specs } from '../../actions/protocol.js';
73
76
  import { query_put_fact } from '../../db/fact_queries.js';
74
77
  import { ROLE_ADMIN, ROLE_KEEPER } from '../../auth/role_schema.js';
75
78
  import { auth_integration_truncate_tables } from '../db.js';
76
- import { query_schema_snapshot, SchemaSnapshot } from '../schema_introspect.js';
79
+ import { query_schema_snapshot, SchemaSnapshot, query_migration_tracker, MigrationTracker, } from '../schema_introspect.js';
77
80
  import { ActionManifest, build_action_manifest } from './action_manifest.js';
78
81
  import { query_create_actor } from '../../auth/account_queries.js';
79
82
  import { create_test_account_with_credentials, mint_test_session } from '../app_server.js';
@@ -302,6 +305,38 @@ export const testing_schema_snapshot_action_spec = {
302
305
  * `create_testing_actions`; mount directly for in-process use.
303
306
  */
304
307
  export const create_testing_schema_snapshot_action = () => rpc_action(testing_schema_snapshot_action_spec, async (input, ctx) => query_schema_snapshot(ctx.db, { exclude_tables: input.exclude_tables }));
308
+ /**
309
+ * `_testing_migration_tracker` — dump the `schema_version` tracker rows as a
310
+ * normalized `MigrationTracker` (`[{namespace, name, sequence}]`) for
311
+ * cross-impl migration-identity diffing. The provenance half of
312
+ * `_testing_schema_snapshot`: where that captures the resulting *schema*
313
+ * (and excludes the tracker by design), this captures the tracker *itself*,
314
+ * so the cross-backend harness can assert the two spines record byte-identical
315
+ * migration identity. This closes the gap that let the cell/fact
316
+ * migration-name divergence reach the visiones cutover undetected
317
+ * (`name-divergence-at-N` — same schema, divergent recorded names).
318
+ *
319
+ * `auth` gates on the daemon-token credential, matching `_testing_reset`. The
320
+ * Rust mirror is `fuz_testing::create_testing_migration_tracker_action_spec`.
321
+ */
322
+ export const testing_migration_tracker_action_spec = {
323
+ method: '_testing_migration_tracker',
324
+ kind: 'request_response',
325
+ initiator: 'frontend',
326
+ auth: TESTING_ACTION_AUTH,
327
+ side_effects: false,
328
+ input: z.strictObject({}),
329
+ output: MigrationTracker,
330
+ async: true,
331
+ description: 'Test-binary only — dump the schema_version tracker rows as a normalized {namespace, name, ' +
332
+ 'sequence} list for cross-impl migration-identity parity diffing.',
333
+ };
334
+ /**
335
+ * Build the standalone `_testing_migration_tracker` action. No deps — reads
336
+ * `ctx.db`'s `schema_version` via `query_migration_tracker`. Bundled by
337
+ * `create_testing_actions`; mount directly for in-process use.
338
+ */
339
+ export const create_testing_migration_tracker_action = () => rpc_action(testing_migration_tracker_action_spec, async (_input, ctx) => query_migration_tracker(ctx.db));
305
340
  /**
306
341
  * `_testing_action_manifest` — dump the backend's live RPC method set as a
307
342
  * normalized `ActionManifest` (one entry per method: `{method, side_effects,
@@ -495,6 +530,7 @@ export const create_testing_actions = (deps, options) => {
495
530
  }),
496
531
  create_testing_drain_effects_action(),
497
532
  create_testing_schema_snapshot_action(),
533
+ create_testing_migration_tracker_action(),
498
534
  ];
499
535
  };
500
536
  /** Set of auth-namespace tables `_testing_reset` wipes. Mirrored by the coverage test. */
@@ -109,6 +109,45 @@ export declare const SchemaSnapshot: z.ZodObject<{
109
109
  }, z.core.$strip>>;
110
110
  }, z.core.$strip>;
111
111
  export type SchemaSnapshot = z.infer<typeof SchemaSnapshot>;
112
+ /**
113
+ * A single `schema_version` tracker row — the migration-identity primitive.
114
+ *
115
+ * Where `SchemaSnapshot` is provenance-agnostic (it captures the resulting
116
+ * tables and deliberately *excludes* the tracker), this **is** the tracker:
117
+ * the `(namespace, name, sequence)` the migration runner records per applied
118
+ * migration. `sequence` carries order; `name` carries identity (the PK is
119
+ * `(namespace, name)`). The cross-impl gate diffs these between the two
120
+ * bootstrapped spines so a migration-name or partitioning drift — invisible
121
+ * to the schema snapshot — is a gated fact, not a latent interop break.
122
+ */
123
+ export declare const MigrationTrackerEntry: z.ZodObject<{
124
+ namespace: z.ZodString;
125
+ name: z.ZodString;
126
+ sequence: z.ZodNumber;
127
+ }, z.core.$strip>;
128
+ export type MigrationTrackerEntry = z.infer<typeof MigrationTrackerEntry>;
129
+ /**
130
+ * The full `schema_version` tracker as a deterministically-ordered list,
131
+ * wrapped in an object so it round-trips cleanly as a JSON-RPC result.
132
+ * Sorted by `(namespace, sequence)` on capture.
133
+ */
134
+ export declare const MigrationTracker: z.ZodObject<{
135
+ entries: z.ZodArray<z.ZodObject<{
136
+ namespace: z.ZodString;
137
+ name: z.ZodString;
138
+ sequence: z.ZodNumber;
139
+ }, z.core.$strip>>;
140
+ }, z.core.$strip>;
141
+ export type MigrationTracker = z.infer<typeof MigrationTracker>;
142
+ /**
143
+ * Read every `schema_version` row into a deterministic `MigrationTracker`.
144
+ *
145
+ * The migration-identity twin of `query_schema_snapshot`: that captures the
146
+ * resulting schema (and excludes this tracker); this captures the tracker
147
+ * rows themselves, so the cross-impl gate can assert the two spines record
148
+ * byte-identical migration identity.
149
+ */
150
+ export declare const query_migration_tracker: (db: Db) => Promise<MigrationTracker>;
112
151
  /** Filter options for `query_schema_snapshot`. */
113
152
  export interface QuerySchemaSnapshotOptions {
114
153
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"schema_introspect.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/schema_introspect.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAE7B;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB,OAAO,KAAK,EAAC,EAAE,EAAC,MAAM,aAAa,CAAC;AAEpC;;;;;GAKG;AACH,eAAO,MAAM,cAAc;;;;;;iBAWzB,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAE5D,qCAAqC;AACrC,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;iBAOxB,CAAC;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAE1D,qFAAqF;AACrF,eAAO,MAAM,gBAAgB;;iBAE3B,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAEhE;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB;;iBAG3B,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAEhE;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;iBAOzB,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAE5D,kDAAkD;AAClD,MAAM,WAAW,0BAA0B;IAC1C;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CAChD;AA8DD;;;;;;;;;GASG;AACH,eAAO,MAAM,qBAAqB,GACjC,IAAI,EAAE,EACN,UAAS,0BAA+B,KACtC,OAAO,CAAC,cAAc,CAyHxB,CAAC"}
1
+ {"version":3,"file":"schema_introspect.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/schema_introspect.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAE7B;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB,OAAO,KAAK,EAAC,EAAE,EAAC,MAAM,aAAa,CAAC;AAEpC;;;;;GAKG;AACH,eAAO,MAAM,cAAc;;;;;;iBAWzB,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAE5D,qCAAqC;AACrC,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;iBAOxB,CAAC;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAE1D,qFAAqF;AACrF,eAAO,MAAM,gBAAgB;;iBAE3B,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAEhE;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB;;iBAG3B,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAEhE;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;iBAOzB,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAE5D;;;;;;;;;;GAUG;AACH,eAAO,MAAM,qBAAqB;;;;iBAOhC,CAAC;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAE1E;;;;GAIG;AACH,eAAO,MAAM,gBAAgB;;;;;;iBAE3B,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAEhE;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,GAAU,IAAI,EAAE,KAAG,OAAO,CAAC,gBAAgB,CAa9E,CAAC;AAEF,kDAAkD;AAClD,MAAM,WAAW,0BAA0B;IAC1C;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CAChD;AA8DD;;;;;;;;;GASG;AACH,eAAO,MAAM,qBAAqB,GACjC,IAAI,EAAE,EACN,UAAS,0BAA+B,KACtC,OAAO,CAAC,cAAc,CAyHxB,CAAC"}
@@ -81,6 +81,53 @@ export const SchemaSnapshot = z.object({
81
81
  /** Enum types (`CREATE TYPE ... AS ENUM`) keyed by name; labels in declared order. */
82
82
  enums: z.record(z.string(), EnumTypeSnapshot),
83
83
  });
84
+ /**
85
+ * A single `schema_version` tracker row — the migration-identity primitive.
86
+ *
87
+ * Where `SchemaSnapshot` is provenance-agnostic (it captures the resulting
88
+ * tables and deliberately *excludes* the tracker), this **is** the tracker:
89
+ * the `(namespace, name, sequence)` the migration runner records per applied
90
+ * migration. `sequence` carries order; `name` carries identity (the PK is
91
+ * `(namespace, name)`). The cross-impl gate diffs these between the two
92
+ * bootstrapped spines so a migration-name or partitioning drift — invisible
93
+ * to the schema snapshot — is a gated fact, not a latent interop break.
94
+ */
95
+ export const MigrationTrackerEntry = z.object({
96
+ /** Migration namespace (e.g. `fuz_cell`, `fuz_cell_history`). */
97
+ namespace: z.string(),
98
+ /** Migration name within the namespace (e.g. `full_cell_schema`). */
99
+ name: z.string(),
100
+ /** Per-namespace apply order, starting at 0. */
101
+ sequence: z.number().int(),
102
+ });
103
+ /**
104
+ * The full `schema_version` tracker as a deterministically-ordered list,
105
+ * wrapped in an object so it round-trips cleanly as a JSON-RPC result.
106
+ * Sorted by `(namespace, sequence)` on capture.
107
+ */
108
+ export const MigrationTracker = z.object({
109
+ entries: z.array(MigrationTrackerEntry),
110
+ });
111
+ /**
112
+ * Read every `schema_version` row into a deterministic `MigrationTracker`.
113
+ *
114
+ * The migration-identity twin of `query_schema_snapshot`: that captures the
115
+ * resulting schema (and excludes this tracker); this captures the tracker
116
+ * rows themselves, so the cross-impl gate can assert the two spines record
117
+ * byte-identical migration identity.
118
+ */
119
+ export const query_migration_tracker = async (db) => {
120
+ const rows = await db.query(`SELECT namespace, name, sequence
121
+ FROM schema_version
122
+ ORDER BY namespace ASC, sequence ASC`);
123
+ return {
124
+ entries: rows.map((r) => ({
125
+ namespace: r.namespace,
126
+ name: r.name,
127
+ sequence: r.sequence,
128
+ })),
129
+ };
130
+ };
84
131
  const sort_keys = (record) => {
85
132
  const sorted = {};
86
133
  for (const key of Object.keys(record).sort()) {
@@ -39,7 +39,7 @@ import './assert_dev_env.js';
39
39
  *
40
40
  * @module
41
41
  */
42
- import type { ColumnSnapshot, SchemaSnapshot } from './schema_introspect.js';
42
+ import type { ColumnSnapshot, MigrationTracker, SchemaSnapshot } from './schema_introspect.js';
43
43
  /** Structured drift entry. `where` is the named source impl ('a' or 'b'). */
44
44
  export type SchemaDiff = {
45
45
  readonly kind: 'table_only_in';
@@ -139,4 +139,45 @@ export declare const format_schema_diffs: (diffs: ReadonlyArray<SchemaDiff>, lab
139
139
  * ```
140
140
  */
141
141
  export declare const assert_schema_snapshots_equal: (a: SchemaSnapshot, b: SchemaSnapshot, labels?: SchemaDiffLabels) => void;
142
+ /**
143
+ * Structured migration-identity drift entry. Keyed on `(namespace, name)` —
144
+ * the `schema_version` PK — so a name rename and a partitioning change both
145
+ * surface as `tracker_row_only_in`, and a re-order surfaces as
146
+ * `tracker_sequence_differs`.
147
+ */
148
+ export type MigrationTrackerDiff = {
149
+ readonly kind: 'tracker_row_only_in';
150
+ readonly where: 'a' | 'b';
151
+ readonly namespace: string;
152
+ readonly name: string;
153
+ } | {
154
+ readonly kind: 'tracker_sequence_differs';
155
+ readonly namespace: string;
156
+ readonly name: string;
157
+ readonly a: number;
158
+ readonly b: number;
159
+ };
160
+ /**
161
+ * Structural diff between two migration trackers — empty array means the two
162
+ * spines recorded byte-identical migration identity. Keyed on
163
+ * `(namespace, name)`; sequence mismatches on a shared key are reported too.
164
+ * Deterministic order: shared/missing rows in sorted `(namespace, name)` order.
165
+ */
166
+ export declare const diff_migration_trackers: (a: MigrationTracker, b: MigrationTracker) => Array<MigrationTrackerDiff>;
167
+ /**
168
+ * Render migration-tracker diffs as a human-readable multi-line string.
169
+ * Empty diffs produce an empty string.
170
+ */
171
+ export declare const format_migration_tracker_diffs: (diffs: ReadonlyArray<MigrationTrackerDiff>, labels?: SchemaDiffLabels) => string;
172
+ /**
173
+ * Throw if the two spines' `schema_version` trackers disagree — the gate for
174
+ * the swap-freely invariant (any consumer can swap TS↔Rust over one DB without
175
+ * re-bootstrapping). This catches what `assert_schema_snapshots_equal` is blind
176
+ * to by design: the snapshot excludes the tracker, so a migration-name or
177
+ * partitioning divergence that yields an identical *schema* (e.g. `cell_v0` vs
178
+ * `full_cell_schema`, or `cell_history` bundled vs isolated) passes schema
179
+ * parity but breaks the runner's positional name-prefix check at boot
180
+ * (`name-divergence-at-N`). The error names the impls and lists every diff.
181
+ */
182
+ export declare const assert_migration_trackers_equal: (a: MigrationTracker, b: MigrationTracker, labels?: SchemaDiffLabels) => void;
142
183
  //# sourceMappingURL=schema_parity.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"schema_parity.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/schema_parity.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"schema_parity.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/schema_parity.ts"],"names":[],"mappings":"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"}
@@ -225,3 +225,94 @@ export const assert_schema_snapshots_equal = (a, b, labels = {}) => {
225
225
  const label_b = labels.b ?? 'b';
226
226
  throw new Error(`Schema parity failed: ${diffs.length} diff(s) between ${label_a} and ${label_b}\n${format_schema_diffs(diffs, labels)}`);
227
227
  };
228
+ const tracker_key = (namespace, name) => `${namespace}${name}`;
229
+ /**
230
+ * Structural diff between two migration trackers — empty array means the two
231
+ * spines recorded byte-identical migration identity. Keyed on
232
+ * `(namespace, name)`; sequence mismatches on a shared key are reported too.
233
+ * Deterministic order: shared/missing rows in sorted `(namespace, name)` order.
234
+ */
235
+ export const diff_migration_trackers = (a, b) => {
236
+ const diffs = [];
237
+ const a_by_key = new Map(a.entries.map((e) => [tracker_key(e.namespace, e.name), e]));
238
+ const b_by_key = new Map(b.entries.map((e) => [tracker_key(e.namespace, e.name), e]));
239
+ // Union keyed by `(namespace, name)`; the value is a reference entry (from
240
+ // whichever side has it) used to recover namespace/name for the diff — so a
241
+ // row present on only one side needs no non-null assertion.
242
+ const by_key = new Map([...a_by_key, ...b_by_key]);
243
+ for (const [key, ref] of [...by_key].sort((x, y) => (x[0] < y[0] ? -1 : x[0] > y[0] ? 1 : 0))) {
244
+ const ea = a_by_key.get(key);
245
+ const eb = b_by_key.get(key);
246
+ if (!ea) {
247
+ diffs.push({
248
+ kind: 'tracker_row_only_in',
249
+ where: 'b',
250
+ namespace: ref.namespace,
251
+ name: ref.name,
252
+ });
253
+ continue;
254
+ }
255
+ if (!eb) {
256
+ diffs.push({
257
+ kind: 'tracker_row_only_in',
258
+ where: 'a',
259
+ namespace: ref.namespace,
260
+ name: ref.name,
261
+ });
262
+ continue;
263
+ }
264
+ if (ea.sequence !== eb.sequence) {
265
+ diffs.push({
266
+ kind: 'tracker_sequence_differs',
267
+ namespace: ea.namespace,
268
+ name: ea.name,
269
+ a: ea.sequence,
270
+ b: eb.sequence,
271
+ });
272
+ }
273
+ }
274
+ return diffs;
275
+ };
276
+ /**
277
+ * Render migration-tracker diffs as a human-readable multi-line string.
278
+ * Empty diffs produce an empty string.
279
+ */
280
+ export const format_migration_tracker_diffs = (diffs, labels = {}) => {
281
+ if (diffs.length === 0)
282
+ return '';
283
+ const label_a = labels.a ?? 'a';
284
+ const label_b = labels.b ?? 'b';
285
+ const lines = [];
286
+ for (const d of diffs) {
287
+ switch (d.kind) {
288
+ case 'tracker_row_only_in':
289
+ lines.push(` migration ${d.namespace}/${d.name} only in ${d.where === 'a' ? label_a : label_b}`);
290
+ break;
291
+ case 'tracker_sequence_differs':
292
+ lines.push(` migration ${d.namespace}/${d.name} sequence differs: ${label_a}=${d.a}, ${label_b}=${d.b}`);
293
+ break;
294
+ default:
295
+ d;
296
+ break;
297
+ }
298
+ }
299
+ return lines.join('\n');
300
+ };
301
+ /**
302
+ * Throw if the two spines' `schema_version` trackers disagree — the gate for
303
+ * the swap-freely invariant (any consumer can swap TS↔Rust over one DB without
304
+ * re-bootstrapping). This catches what `assert_schema_snapshots_equal` is blind
305
+ * to by design: the snapshot excludes the tracker, so a migration-name or
306
+ * partitioning divergence that yields an identical *schema* (e.g. `cell_v0` vs
307
+ * `full_cell_schema`, or `cell_history` bundled vs isolated) passes schema
308
+ * parity but breaks the runner's positional name-prefix check at boot
309
+ * (`name-divergence-at-N`). The error names the impls and lists every diff.
310
+ */
311
+ export const assert_migration_trackers_equal = (a, b, labels = {}) => {
312
+ const diffs = diff_migration_trackers(a, b);
313
+ if (diffs.length === 0)
314
+ return;
315
+ const label_a = labels.a ?? 'a';
316
+ const label_b = labels.b ?? 'b';
317
+ throw new Error(`Migration-identity parity failed: ${diffs.length} diff(s) between ${label_a} and ${label_b}\n${format_migration_tracker_diffs(diffs, labels)}`);
318
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fuzdev/fuz_app",
3
- "version": "0.98.0",
3
+ "version": "0.99.0",
4
4
  "description": "fullstack app library",
5
5
  "glyph": "🗝",
6
6
  "logo": "logo.svg",