@fuzdev/fuz_app 0.70.0 → 0.71.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.
package/dist/db/CLAUDE.md CHANGED
@@ -80,10 +80,10 @@ Content-addressed byte store. Cells reference facts by blake3 hash
80
80
  (`cell.refs`, auto-extracted from `data`); the fact layer stores the bytes.
81
81
  Optional — minimal consumers never migrate it.
82
82
 
83
- - **`fact_ddl.ts`** — `facts` (content-addressed bytes: embedded `bytes` xor
84
- `external_url`, CHECK enforces exactly one) + `fact_refs` (declared
83
+ - **`fact_ddl.ts`** — `fact` (content-addressed bytes: embedded `bytes` xor
84
+ `external_url`, CHECK enforces exactly one) + `fact_ref` (declared
85
85
  dependency edges; `target_hash` deliberately not an FK, for federation) +
86
- `memos` (`(fn_id, input_hash) → output_hash`). `FACT_MIGRATION_NS`, namespace
86
+ `memo` (`(fn_id, input_hash) → output_hash`). `FACT_MIGRATION_NS`, namespace
87
87
  `fuz_facts`.
88
88
  - **`fact_queries.ts`** — mechanical `query_put_fact` (idempotent `ON CONFLICT
89
89
  DO NOTHING`), `_put_fact_refs`, `_get_fact` / `_get_fact_meta` / `_has_fact`
@@ -8,7 +8,7 @@
8
8
  * downstream code can target a stable schema. The table ships
9
9
  * present-but-unwritten.
10
10
  *
11
- * `fact_hash` is intentionally **not** a foreign key to `facts(hash)` —
11
+ * `fact_hash` is intentionally **not** a foreign key to `fact(hash)` —
12
12
  * snapshots may be evicted by GC policy while history rows remain as audit
13
13
  * traces, and federation may target facts on another instance.
14
14
  *
@@ -8,7 +8,7 @@
8
8
  * downstream code can target a stable schema. The table ships
9
9
  * present-but-unwritten.
10
10
  *
11
- * `fact_hash` is intentionally **not** a foreign key to `facts(hash)` —
11
+ * `fact_hash` is intentionally **not** a foreign key to `fact(hash)` —
12
12
  * snapshots may be evicted by GC policy while history rows remain as audit
13
13
  * traces, and federation may target facts on another instance.
14
14
  *
@@ -3,32 +3,32 @@
3
3
  *
4
4
  * Three tables:
5
5
  *
6
- * - `facts` — content-addressed bytes. `hash = 'blake3:<hex64>'`. Either
6
+ * - `fact` — content-addressed bytes. `hash = 'blake3:<hex64>'`. Either
7
7
  * embedded (`bytes`) or referenced (`external_url`); the CHECK constraint
8
8
  * enforces exactly one populated. Idempotent: same bytes always produce
9
9
  * the same hash, so `INSERT … ON CONFLICT DO NOTHING` is the put primitive.
10
- * - `fact_refs` — declared dependency edges (source fact → target fact).
10
+ * - `fact_ref` — declared dependency edges (source fact → target fact).
11
11
  * `target_hash` is intentionally **not** a foreign key: in federation a
12
12
  * reference may target a fact stored on another instance.
13
- * - `memos` — `(fn_id, input_hash) → output_hash` for memoized computations.
13
+ * - `memo` — `(fn_id, input_hash) → output_hash` for memoized computations.
14
14
  *
15
15
  * @module
16
16
  */
17
17
  import type { Migration, MigrationNamespace } from './migrate.js';
18
- /** `facts` table — content-addressed byte store. */
19
- export declare const FACTS_SCHEMA = "\nCREATE TABLE IF NOT EXISTS facts (\n\thash TEXT PRIMARY KEY,\n\tbytes BYTEA,\n\texternal_url TEXT,\n\tcontent_type TEXT,\n\tsize BIGINT NOT NULL,\n\tcreated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n\tCONSTRAINT facts_storage_present CHECK (bytes IS NOT NULL OR external_url IS NOT NULL)\n)";
18
+ /** `fact` table — content-addressed byte store. */
19
+ export declare const FACTS_SCHEMA = "\nCREATE TABLE IF NOT EXISTS fact (\n\thash TEXT PRIMARY KEY,\n\tbytes BYTEA,\n\texternal_url TEXT,\n\tcontent_type TEXT,\n\tsize BIGINT NOT NULL,\n\tcreated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n\tCONSTRAINT fact_storage_present CHECK (bytes IS NOT NULL OR external_url IS NOT NULL)\n)";
20
20
  /**
21
- * `fact_refs` table — declared dependency edges between facts.
21
+ * `fact_ref` table — declared dependency edges between facts.
22
22
  *
23
23
  * `target_hash` is not a foreign key (federation: target may live remotely).
24
24
  */
25
- export declare const FACT_REFS_SCHEMA = "\nCREATE TABLE IF NOT EXISTS fact_refs (\n\tsource_hash TEXT NOT NULL REFERENCES facts(hash) ON DELETE CASCADE,\n\ttarget_hash TEXT NOT NULL,\n\tPRIMARY KEY (source_hash, target_hash)\n)";
25
+ export declare const FACT_REFS_SCHEMA = "\nCREATE TABLE IF NOT EXISTS fact_ref (\n\tsource_hash TEXT NOT NULL REFERENCES fact(hash) ON DELETE CASCADE,\n\ttarget_hash TEXT NOT NULL,\n\tPRIMARY KEY (source_hash, target_hash)\n)";
26
26
  /** Reverse lookup: which facts reference a given target? */
27
- export declare const FACT_REFS_TARGET_INDEX = "\nCREATE INDEX IF NOT EXISTS idx_fact_refs_target ON fact_refs(target_hash)";
28
- /** `memos` table — `(fn_id, input_hash) → output_hash` for memoized computations. */
29
- export declare const MEMOS_SCHEMA = "\nCREATE TABLE IF NOT EXISTS memos (\n\tfn_id TEXT NOT NULL,\n\tinput_hash TEXT NOT NULL,\n\toutput_hash TEXT NOT NULL,\n\tcreated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n\tPRIMARY KEY (fn_id, input_hash)\n)";
27
+ export declare const FACT_REFS_TARGET_INDEX = "\nCREATE INDEX IF NOT EXISTS idx_fact_ref_target ON fact_ref(target_hash)";
28
+ /** `memo` table — `(fn_id, input_hash) → output_hash` for memoized computations. */
29
+ export declare const MEMOS_SCHEMA = "\nCREATE TABLE IF NOT EXISTS memo (\n\tfn_id TEXT NOT NULL,\n\tinput_hash TEXT NOT NULL,\n\toutput_hash TEXT NOT NULL,\n\tcreated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n\tPRIMARY KEY (fn_id, input_hash)\n)";
30
30
  /** Tables created by `FACT_MIGRATION_NS`, in drop order (children first). */
31
- export declare const FACT_DROP_TABLES: readonly ["memos", "fact_refs", "facts"];
31
+ export declare const FACT_DROP_TABLES: readonly ["memo", "fact_ref", "fact"];
32
32
  /** Fact + memo migrations. */
33
33
  export declare const FACT_MIGRATIONS: Array<Migration>;
34
34
  /** Namespace identifier for fact + memo migrations. */
@@ -1 +1 @@
1
- {"version":3,"file":"fact_ddl.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/db/fact_ddl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAC,SAAS,EAAE,kBAAkB,EAAC,MAAM,cAAc,CAAC;AAEhE,oDAAoD;AACpD,eAAO,MAAM,YAAY,uSASvB,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,+LAK3B,CAAC;AAEH,4DAA4D;AAC5D,eAAO,MAAM,sBAAsB,gFACuC,CAAC;AAE3E,qFAAqF;AACrF,eAAO,MAAM,YAAY,oNAOvB,CAAC;AAEH,6EAA6E;AAC7E,eAAO,MAAM,gBAAgB,0CAA2C,CAAC;AAEzE,8BAA8B;AAC9B,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,SAAS,CAU5C,CAAC;AAEF,uDAAuD;AACvD,eAAO,MAAM,wBAAwB,cAAc,CAAC;AAEpD,wDAAwD;AACxD,eAAO,MAAM,iBAAiB,EAAE,kBAG/B,CAAC"}
1
+ {"version":3,"file":"fact_ddl.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/db/fact_ddl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAC,SAAS,EAAE,kBAAkB,EAAC,MAAM,cAAc,CAAC;AAEhE,mDAAmD;AACnD,eAAO,MAAM,YAAY,qSASvB,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,6LAK3B,CAAC;AAEH,4DAA4D;AAC5D,eAAO,MAAM,sBAAsB,8EACqC,CAAC;AAEzE,oFAAoF;AACpF,eAAO,MAAM,YAAY,mNAOvB,CAAC;AAEH,6EAA6E;AAC7E,eAAO,MAAM,gBAAgB,uCAAwC,CAAC;AAEtE,8BAA8B;AAC9B,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,SAAS,CAU5C,CAAC;AAEF,uDAAuD;AACvD,eAAO,MAAM,wBAAwB,cAAc,CAAC;AAEpD,wDAAwD;AACxD,eAAO,MAAM,iBAAiB,EAAE,kBAG/B,CAAC"}
@@ -3,45 +3,45 @@
3
3
  *
4
4
  * Three tables:
5
5
  *
6
- * - `facts` — content-addressed bytes. `hash = 'blake3:<hex64>'`. Either
6
+ * - `fact` — content-addressed bytes. `hash = 'blake3:<hex64>'`. Either
7
7
  * embedded (`bytes`) or referenced (`external_url`); the CHECK constraint
8
8
  * enforces exactly one populated. Idempotent: same bytes always produce
9
9
  * the same hash, so `INSERT … ON CONFLICT DO NOTHING` is the put primitive.
10
- * - `fact_refs` — declared dependency edges (source fact → target fact).
10
+ * - `fact_ref` — declared dependency edges (source fact → target fact).
11
11
  * `target_hash` is intentionally **not** a foreign key: in federation a
12
12
  * reference may target a fact stored on another instance.
13
- * - `memos` — `(fn_id, input_hash) → output_hash` for memoized computations.
13
+ * - `memo` — `(fn_id, input_hash) → output_hash` for memoized computations.
14
14
  *
15
15
  * @module
16
16
  */
17
- /** `facts` table — content-addressed byte store. */
17
+ /** `fact` table — content-addressed byte store. */
18
18
  export const FACTS_SCHEMA = `
19
- CREATE TABLE IF NOT EXISTS facts (
19
+ CREATE TABLE IF NOT EXISTS fact (
20
20
  hash TEXT PRIMARY KEY,
21
21
  bytes BYTEA,
22
22
  external_url TEXT,
23
23
  content_type TEXT,
24
24
  size BIGINT NOT NULL,
25
25
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
26
- CONSTRAINT facts_storage_present CHECK (bytes IS NOT NULL OR external_url IS NOT NULL)
26
+ CONSTRAINT fact_storage_present CHECK (bytes IS NOT NULL OR external_url IS NOT NULL)
27
27
  )`;
28
28
  /**
29
- * `fact_refs` table — declared dependency edges between facts.
29
+ * `fact_ref` table — declared dependency edges between facts.
30
30
  *
31
31
  * `target_hash` is not a foreign key (federation: target may live remotely).
32
32
  */
33
33
  export const FACT_REFS_SCHEMA = `
34
- CREATE TABLE IF NOT EXISTS fact_refs (
35
- source_hash TEXT NOT NULL REFERENCES facts(hash) ON DELETE CASCADE,
34
+ CREATE TABLE IF NOT EXISTS fact_ref (
35
+ source_hash TEXT NOT NULL REFERENCES fact(hash) ON DELETE CASCADE,
36
36
  target_hash TEXT NOT NULL,
37
37
  PRIMARY KEY (source_hash, target_hash)
38
38
  )`;
39
39
  /** Reverse lookup: which facts reference a given target? */
40
40
  export const FACT_REFS_TARGET_INDEX = `
41
- CREATE INDEX IF NOT EXISTS idx_fact_refs_target ON fact_refs(target_hash)`;
42
- /** `memos` table — `(fn_id, input_hash) → output_hash` for memoized computations. */
41
+ CREATE INDEX IF NOT EXISTS idx_fact_ref_target ON fact_ref(target_hash)`;
42
+ /** `memo` table — `(fn_id, input_hash) → output_hash` for memoized computations. */
43
43
  export const MEMOS_SCHEMA = `
44
- CREATE TABLE IF NOT EXISTS memos (
44
+ CREATE TABLE IF NOT EXISTS memo (
45
45
  fn_id TEXT NOT NULL,
46
46
  input_hash TEXT NOT NULL,
47
47
  output_hash TEXT NOT NULL,
@@ -49,7 +49,7 @@ CREATE TABLE IF NOT EXISTS memos (
49
49
  PRIMARY KEY (fn_id, input_hash)
50
50
  )`;
51
51
  /** Tables created by `FACT_MIGRATION_NS`, in drop order (children first). */
52
- export const FACT_DROP_TABLES = ['memos', 'fact_refs', 'facts'];
52
+ export const FACT_DROP_TABLES = ['memo', 'fact_ref', 'fact'];
53
53
  /** Fact + memo migrations. */
54
54
  export const FACT_MIGRATIONS = [
55
55
  {
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Raw queries against the `facts` and `fact_refs` tables.
2
+ * Raw queries against the `fact` and `fact_ref` tables.
3
3
  *
4
4
  * Convention: `deps: QueryDeps` first, no audit side effects, mutations are
5
5
  * idempotent (`ON CONFLICT DO NOTHING`) so the same hash can be written by
@@ -13,7 +13,7 @@
13
13
  */
14
14
  import type { QueryDeps } from './query_deps.js';
15
15
  import type { FactHash } from '@fuzdev/fuz_util/fact_hash.js';
16
- /** Row shape for `SELECT … FROM facts`. */
16
+ /** Row shape for `SELECT … FROM fact`. */
17
17
  export interface FactRow {
18
18
  hash: FactHash;
19
19
  bytes: Uint8Array | null;
@@ -33,11 +33,11 @@ export interface FactMetaRow {
33
33
  /**
34
34
  * Idempotently insert a fact row.
35
35
  *
36
- * `bytes` xor `external_url` per the `facts_storage_present` CHECK
36
+ * `bytes` xor `external_url` per the `fact_storage_present` CHECK
37
37
  * constraint; the caller is responsible for satisfying it (the queries
38
38
  * layer does not second-guess). Returns `true` when a new row was
39
39
  * inserted, `false` when a row already existed (caller can use this to
40
- * decide whether to also write `fact_refs`).
40
+ * decide whether to also write `fact_ref`).
41
41
  */
42
42
  export declare const query_put_fact: (deps: QueryDeps, input: {
43
43
  hash: FactHash;
@@ -62,7 +62,7 @@ export declare const query_get_fact: (deps: QueryDeps, hash: FactHash) => Promis
62
62
  */
63
63
  export declare const query_get_fact_meta: (deps: QueryDeps, hash: FactHash) => Promise<FactMetaRow | null>;
64
64
  /**
65
- * Cheap existence check. Backed by the `facts` PK index.
65
+ * Cheap existence check. Backed by the `fact` PK index.
66
66
  */
67
67
  export declare const query_has_fact: (deps: QueryDeps, hash: FactHash) => Promise<boolean>;
68
68
  /**
@@ -71,7 +71,7 @@ export declare const query_has_fact: (deps: QueryDeps, hash: FactHash) => Promis
71
71
  */
72
72
  export declare const query_get_fact_refs: (deps: QueryDeps, source_hash: FactHash) => Promise<Array<FactHash>>;
73
73
  /**
74
- * Drop a fact row. Cascades `fact_refs` rows via the `ON DELETE CASCADE`
74
+ * Drop a fact row. Cascades `fact_ref` rows via the `ON DELETE CASCADE`
75
75
  * FK on `source_hash`. Returns the deleted row's `(size, external_url)`
76
76
  * so the caller can unlink the disk file (if any) and tally freed bytes,
77
77
  * or `null` when no row matched (idempotent: deleting an absent fact is
@@ -104,17 +104,17 @@ export interface OrphanFactsListResult {
104
104
  }>;
105
105
  }
106
106
  /**
107
- * Compute the "orphan facts" set: rows in `facts` where no active
107
+ * Compute the "orphan facts" set: rows in `fact` where no active
108
108
  * (non-tombstone) `cell.refs` array contains the hash.
109
109
  *
110
- * The `cell` join is deliberately app-coupled — `facts` lives in the
110
+ * The `cell` join is deliberately app-coupled — `fact` lives in the
111
111
  * `fuz_facts` namespace and `cell.refs` lives in `fuz_cell`, but the
112
112
  * orphan predicate only makes sense in apps that route content through
113
113
  * cells. When a non-cell fact consumer ever appears (signed memo
114
114
  * outputs? external fact mirrors?) the predicate moves to a generic
115
115
  * `fact_consumers` registry; today the cell layer is the only consumer.
116
116
  *
117
- * The `older_than` filter applies to `facts.created_at`. Pass `null`
117
+ * The `older_than` filter applies to `fact.created_at`. Pass `null`
118
118
  * to skip the filter (used by the list-summary preview); the delete
119
119
  * handler always passes a non-null cutoff (default 0, meaning "any
120
120
  * orphan").
@@ -1 +1 @@
1
- {"version":3,"file":"fact_queries.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/db/fact_queries.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,iBAAiB,CAAC;AAE/C,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,+BAA+B,CAAC;AAE5D,2CAA2C;AAC3C,MAAM,WAAW,OAAO;IACvB,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;IACzB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,UAAU,EAAE,IAAI,CAAC;CACjB;AAED,qEAAqE;AACrE,MAAM,WAAW,WAAW;IAC3B,IAAI,EAAE,QAAQ,CAAC;IACf,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,UAAU,EAAE,IAAI,CAAC;CACjB;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,GAC1B,MAAM,SAAS,EACf,OAAO;IACN,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;IACzB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,IAAI,EAAE,MAAM,CAAC;CACb,KACC,OAAO,CAAC,OAAO,CASjB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,GAC/B,MAAM,SAAS,EACf,aAAa,QAAQ,EACrB,eAAe,KAAK,CAAC,QAAQ,CAAC,KAC5B,OAAO,CAAC,IAAI,CAQd,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,cAAc,GAAU,MAAM,SAAS,EAAE,MAAM,QAAQ,KAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAO5F,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,mBAAmB,GAC/B,MAAM,SAAS,EACf,MAAM,QAAQ,KACZ,OAAO,CAAC,WAAW,GAAG,IAAI,CAO5B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,cAAc,GAAU,MAAM,SAAS,EAAE,MAAM,QAAQ,KAAG,OAAO,CAAC,OAAO,CAMrF,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,mBAAmB,GAC/B,MAAM,SAAS,EACf,aAAa,QAAQ,KACnB,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAMzB,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,iBAAiB,GAC7B,MAAM,SAAS,EACf,MAAM,QAAQ,KACZ,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;CAAC,GAAG,IAAI,CAQ5D,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,KAAK,CAAC;QACb,IAAI,EAAE,QAAQ,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;KAC5B,CAAC,CAAC;CACH;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,uBAAuB,GACnC,MAAM,SAAS,EACf,YAAY,IAAI,GAAG,IAAI,EACvB,cAAc,MAAM,KAClB,OAAO,CAAC,qBAAqB,CAwC/B,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,oCAAoC,GAChD,MAAM,SAAS,EACf,YAAY,IAAI,KACd,OAAO,CAAC,KAAK,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;CAAC,CAAC,CAiB5E,CAAC"}
1
+ {"version":3,"file":"fact_queries.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/db/fact_queries.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Raw queries against the `facts` and `fact_refs` tables.
2
+ * Raw queries against the `fact` and `fact_ref` tables.
3
3
  *
4
4
  * Convention: `deps: QueryDeps` first, no audit side effects, mutations are
5
5
  * idempotent (`ON CONFLICT DO NOTHING`) so the same hash can be written by
@@ -14,14 +14,14 @@
14
14
  /**
15
15
  * Idempotently insert a fact row.
16
16
  *
17
- * `bytes` xor `external_url` per the `facts_storage_present` CHECK
17
+ * `bytes` xor `external_url` per the `fact_storage_present` CHECK
18
18
  * constraint; the caller is responsible for satisfying it (the queries
19
19
  * layer does not second-guess). Returns `true` when a new row was
20
20
  * inserted, `false` when a row already existed (caller can use this to
21
- * decide whether to also write `fact_refs`).
21
+ * decide whether to also write `fact_ref`).
22
22
  */
23
23
  export const query_put_fact = async (deps, input) => {
24
- const row = await deps.db.query_one(`INSERT INTO facts (hash, bytes, external_url, content_type, size)
24
+ const row = await deps.db.query_one(`INSERT INTO fact (hash, bytes, external_url, content_type, size)
25
25
  VALUES ($1, $2, $3, $4, $5)
26
26
  ON CONFLICT (hash) DO NOTHING
27
27
  RETURNING hash`, [input.hash, input.bytes, input.external_url, input.content_type, input.size]);
@@ -35,7 +35,7 @@ export const query_put_fact = async (deps, input) => {
35
35
  export const query_put_fact_refs = async (deps, source_hash, target_hashes) => {
36
36
  if (target_hashes.length === 0)
37
37
  return;
38
- await deps.db.query(`INSERT INTO fact_refs (source_hash, target_hash)
38
+ await deps.db.query(`INSERT INTO fact_ref (source_hash, target_hash)
39
39
  SELECT $1::text, unnest($2::text[])
40
40
  ON CONFLICT (source_hash, target_hash) DO NOTHING`, [source_hash, target_hashes]);
41
41
  };
@@ -45,7 +45,7 @@ export const query_put_fact_refs = async (deps, source_hash, target_hashes) => {
45
45
  */
46
46
  export const query_get_fact = async (deps, hash) => {
47
47
  const row = await deps.db.query_one(`SELECT hash, bytes, external_url, content_type, size, created_at
48
- FROM facts WHERE hash = $1`, [hash]);
48
+ FROM fact WHERE hash = $1`, [hash]);
49
49
  return row ?? null;
50
50
  };
51
51
  /**
@@ -53,14 +53,14 @@ export const query_get_fact = async (deps, hash) => {
53
53
  */
54
54
  export const query_get_fact_meta = async (deps, hash) => {
55
55
  const row = await deps.db.query_one(`SELECT hash, external_url, content_type, size, created_at
56
- FROM facts WHERE hash = $1`, [hash]);
56
+ FROM fact WHERE hash = $1`, [hash]);
57
57
  return row ?? null;
58
58
  };
59
59
  /**
60
- * Cheap existence check. Backed by the `facts` PK index.
60
+ * Cheap existence check. Backed by the `fact` PK index.
61
61
  */
62
62
  export const query_has_fact = async (deps, hash) => {
63
- const row = await deps.db.query_one(`SELECT EXISTS(SELECT 1 FROM facts WHERE hash = $1) AS exists`, [hash]);
63
+ const row = await deps.db.query_one(`SELECT EXISTS(SELECT 1 FROM fact WHERE hash = $1) AS exists`, [hash]);
64
64
  return row?.exists ?? false;
65
65
  };
66
66
  /**
@@ -68,11 +68,11 @@ export const query_has_fact = async (deps, hash) => {
68
68
  * that need stable ordering should sort.
69
69
  */
70
70
  export const query_get_fact_refs = async (deps, source_hash) => {
71
- const rows = await deps.db.query(`SELECT target_hash FROM fact_refs WHERE source_hash = $1`, [source_hash]);
71
+ const rows = await deps.db.query(`SELECT target_hash FROM fact_ref WHERE source_hash = $1`, [source_hash]);
72
72
  return rows.map((r) => r.target_hash);
73
73
  };
74
74
  /**
75
- * Drop a fact row. Cascades `fact_refs` rows via the `ON DELETE CASCADE`
75
+ * Drop a fact row. Cascades `fact_ref` rows via the `ON DELETE CASCADE`
76
76
  * FK on `source_hash`. Returns the deleted row's `(size, external_url)`
77
77
  * so the caller can unlink the disk file (if any) and tally freed bytes,
78
78
  * or `null` when no row matched (idempotent: deleting an absent fact is
@@ -84,24 +84,24 @@ export const query_get_fact_refs = async (deps, source_hash) => {
84
84
  * `PgFactStore.delete` handles the disk-file unlink.
85
85
  */
86
86
  export const query_delete_fact = async (deps, hash) => {
87
- const row = await deps.db.query_one(`DELETE FROM facts WHERE hash = $1
87
+ const row = await deps.db.query_one(`DELETE FROM fact WHERE hash = $1
88
88
  RETURNING size, external_url`, [hash]);
89
89
  if (!row)
90
90
  return null;
91
91
  return { size: Number(row.size), external_url: row.external_url };
92
92
  };
93
93
  /**
94
- * Compute the "orphan facts" set: rows in `facts` where no active
94
+ * Compute the "orphan facts" set: rows in `fact` where no active
95
95
  * (non-tombstone) `cell.refs` array contains the hash.
96
96
  *
97
- * The `cell` join is deliberately app-coupled — `facts` lives in the
97
+ * The `cell` join is deliberately app-coupled — `fact` lives in the
98
98
  * `fuz_facts` namespace and `cell.refs` lives in `fuz_cell`, but the
99
99
  * orphan predicate only makes sense in apps that route content through
100
100
  * cells. When a non-cell fact consumer ever appears (signed memo
101
101
  * outputs? external fact mirrors?) the predicate moves to a generic
102
102
  * `fact_consumers` registry; today the cell layer is the only consumer.
103
103
  *
104
- * The `older_than` filter applies to `facts.created_at`. Pass `null`
104
+ * The `older_than` filter applies to `fact.created_at`. Pass `null`
105
105
  * to skip the filter (used by the list-summary preview); the delete
106
106
  * handler always passes a non-null cutoff (default 0, meaning "any
107
107
  * orphan").
@@ -113,7 +113,7 @@ export const query_delete_fact = async (deps, hash) => {
113
113
  */
114
114
  export const query_orphan_facts_list = async (deps, older_than, sample_limit) => {
115
115
  const summary = await deps.db.query_one(`SELECT COUNT(*)::bigint AS count, COALESCE(SUM(size), 0)::bigint AS total
116
- FROM facts f
116
+ FROM fact f
117
117
  WHERE NOT EXISTS (
118
118
  SELECT 1 FROM cell c
119
119
  WHERE c.refs @> ARRAY[f.hash]::text[]
@@ -121,7 +121,7 @@ export const query_orphan_facts_list = async (deps, older_than, sample_limit) =>
121
121
  )
122
122
  AND ($1::timestamptz IS NULL OR f.created_at < $1::timestamptz)`, [older_than]);
123
123
  const sample_rows = await deps.db.query(`SELECT hash, size, created_at, external_url
124
- FROM facts f
124
+ FROM fact f
125
125
  WHERE NOT EXISTS (
126
126
  SELECT 1 FROM cell c
127
127
  WHERE c.refs @> ARRAY[f.hash]::text[]
@@ -150,7 +150,7 @@ export const query_orphan_facts_list = async (deps, older_than, sample_limit) =>
150
150
  */
151
151
  export const query_orphan_facts_select_for_delete = async (deps, older_than) => {
152
152
  const rows = await deps.db.query(`SELECT hash, size, external_url
153
- FROM facts f
153
+ FROM fact f
154
154
  WHERE NOT EXISTS (
155
155
  SELECT 1 FROM cell c
156
156
  WHERE c.refs @> ARRAY[f.hash]::text[]
@@ -42,7 +42,7 @@ export declare const create_default_fetcher: () => FactExternalFetcher;
42
42
  * Construction-time deps for `PgFactStore`.
43
43
  *
44
44
  * `embedded_threshold` (bytes) is the inline-vs-external cutoff: payloads
45
- * at or under it store embedded in the `facts` row, larger ones route to
45
+ * at or under it store embedded in the `fact` row, larger ones route to
46
46
  * the external fetcher. Defaults to `FACT_EMBEDDED_THRESHOLD_DEFAULT`
47
47
  * (1 MiB). Consumers tune it per workload — e.g. a much lower bound
48
48
  * (~16 KiB) keeps only small JSON inline and routes image originals +
@@ -86,8 +86,8 @@ export declare class PgFactStore implements FactStore {
86
86
  get_meta(hash: FactHash): Promise<FactMeta | null>;
87
87
  get_refs(hash: FactHash): Promise<Array<FactHash>>;
88
88
  /**
89
- * Drop a fact row. `fact_refs` rows referencing this hash as a source
90
- * cascade via the FK; `fact_refs` targeting this hash do **not** —
89
+ * Drop a fact row. `fact_ref` rows referencing this hash as a source
90
+ * cascade via the FK; `fact_ref` targeting this hash do **not** —
91
91
  * they remain as dangling pointers, consistent with the federation
92
92
  * model where `target_hash` is intentionally not a FK.
93
93
  *
@@ -157,8 +157,8 @@ export class PgFactStore {
157
157
  return query_get_fact_refs(this.#deps, hash);
158
158
  }
159
159
  /**
160
- * Drop a fact row. `fact_refs` rows referencing this hash as a source
161
- * cascade via the FK; `fact_refs` targeting this hash do **not** —
160
+ * Drop a fact row. `fact_ref` rows referencing this hash as a source
161
+ * cascade via the FK; `fact_ref` targeting this hash do **not** —
162
162
  * they remain as dangling pointers, consistent with the federation
163
163
  * model where `target_hash` is intentionally not a FK.
164
164
  *
@@ -209,15 +209,15 @@ test-only by construction.
209
209
 
210
210
  ### `schema_introspect.ts` — `query_schema_snapshot`
211
211
 
212
- - `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 `schema_version` rows.
213
- - `SchemaSnapshot` — fully JSON-serializable; every collection deterministically sorted on capture so structural equality is stable across runs. `applied_at` is excluded from `schema_version` rows so timestamps don't drift the snapshot.
212
+ - `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`), and sequences. The `schema_version` migration tracker is always excluded — it's framework bookkeeping, not domain schema, and impls organize migration namespaces differently.
213
+ - `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.
214
214
 
215
215
  ### `schema_parity.ts` — `assert_schema_snapshots_equal`
216
216
 
217
217
  - `diff_schema_snapshots(a, b)` — structured `Array<SchemaDiff>` between two snapshots; empty array means parity holds.
218
218
  - `format_schema_diffs(diffs, labels?)` — human-readable multi-line rendering; labels name the impl on each side (e.g., `{a: 'deno', b: 'rust'}`).
219
219
  - `assert_schema_snapshots_equal(a, b, labels?)` — throws on drift with a fully-formatted diff message.
220
- - `SchemaDiff` — tagged-union per drift kind: `schema_version_only_in`, `schema_version_sequence_differs`, `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`.
220
+ - `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`.
221
221
 
222
222
  **Cross-impl gate pattern** — a dual-impl consumer running two backends
223
223
  (a TS Hono server and a Rust spine server) against a shared schema, plus
@@ -0,0 +1,59 @@
1
+ import '../assert_dev_env.js';
2
+ /**
3
+ * Vitest `globalSetup` factory for cross-impl **schema-parity** projects.
4
+ *
5
+ * The per-backend `create_cross_backend_global_setup` spawns one backend
6
+ * (derived from the project name). A schema-parity gate instead needs
7
+ * *two* backends alive at once so the test process can capture each one's
8
+ * schema (via `capture_schema_snapshot`) and diff them with
9
+ * `assert_schema_snapshots_equal`. This factory spawns + bootstraps both
10
+ * configs and `provide`s both serialized handles.
11
+ *
12
+ * A consumer's parity `global_setup.ts` collapses to:
13
+ *
14
+ * ```ts
15
+ * import {create_schema_parity_global_setup} from
16
+ * '@fuzdev/fuz_app/testing/cross_backend/create_schema_parity_global_setup.js';
17
+ * import {deno_backend_config, rust_backend_config} from './my_backend_config.js';
18
+ * import './cross_test_types.js'; // augments the two provide keys
19
+ *
20
+ * export default create_schema_parity_global_setup({
21
+ * configs: {a: deno_backend_config, b: rust_backend_config},
22
+ * });
23
+ * ```
24
+ *
25
+ * The parity `.cross.test.ts` `inject`s both keys, rebuilds each with
26
+ * `reconstruct_bootstrapped_handle`, and asserts. Run this project in a
27
+ * later `groupOrder` than the single-backend projects (or with distinct
28
+ * ports) — it reuses both configs' ports, so it must not run concurrently
29
+ * with the per-backend projects.
30
+ *
31
+ * @module
32
+ */
33
+ import type { TestProject } from 'vitest/node';
34
+ import type { BackendConfig } from './backend_config.js';
35
+ export interface SchemaParityGlobalSetupOptions {
36
+ /**
37
+ * The two backend config factories to spawn. `a` is spawned first; on
38
+ * its success `b` is spawned (with `a` torn down if `b` throws). Label
39
+ * them in the parity test via `assert_schema_snapshots_equal`'s labels.
40
+ */
41
+ readonly configs: {
42
+ readonly a: () => BackendConfig;
43
+ readonly b: () => BackendConfig;
44
+ };
45
+ /**
46
+ * `project.provide` keys for the two serialized handles (read by
47
+ * `inject` in the parity test). Default `parity_handle_a` /
48
+ * `parity_handle_b`. Augment vitest's `ProvidedContext` for them.
49
+ */
50
+ readonly provide_keys?: {
51
+ readonly a: string;
52
+ readonly b: string;
53
+ };
54
+ }
55
+ /**
56
+ * Build a vitest `globalSetup` default export that spawns both backends.
57
+ */
58
+ export declare const create_schema_parity_global_setup: ({ configs, provide_keys, }: SchemaParityGlobalSetupOptions) => ((project: TestProject) => Promise<() => Promise<void>>);
59
+ //# sourceMappingURL=create_schema_parity_global_setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create_schema_parity_global_setup.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/create_schema_parity_global_setup.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,aAAa,CAAC;AAE7C,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,qBAAqB,CAAC;AAIvD,MAAM,WAAW,8BAA8B;IAC9C;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE;QAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,aAAa,CAAC;QAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,aAAa,CAAA;KAAC,CAAC;IACrF;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE;QAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAA;KAAC,CAAC;CACjE;AAED;;GAEG;AACH,eAAO,MAAM,iCAAiC,GAAI,4BAG/C,8BAA8B,KAAG,CAAC,CAAC,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,CAmB1F,CAAC"}
@@ -0,0 +1,27 @@
1
+ import '../assert_dev_env.js';
2
+ import { bootstrap_backend } from './bootstrap_backend.js';
3
+ import { serialize_bootstrapped_handle } from './setup.js';
4
+ /**
5
+ * Build a vitest `globalSetup` default export that spawns both backends.
6
+ */
7
+ export const create_schema_parity_global_setup = ({ configs, provide_keys = { a: 'parity_handle_a', b: 'parity_handle_b' }, }) => {
8
+ return async (project) => {
9
+ const a = await bootstrap_backend(configs.a());
10
+ // Tear `a` down if `b` fails to spawn — no orphaned child process.
11
+ let b;
12
+ try {
13
+ b = await bootstrap_backend(configs.b());
14
+ }
15
+ catch (err) {
16
+ await a.teardown();
17
+ throw err;
18
+ }
19
+ const provide = project.provide;
20
+ provide(provide_keys.a, serialize_bootstrapped_handle(a));
21
+ provide(provide_keys.b, serialize_bootstrapped_handle(b));
22
+ return async () => {
23
+ await b.teardown();
24
+ await a.teardown();
25
+ };
26
+ };
27
+ };
@@ -8,6 +8,7 @@ import { type RpcEndpointsSuiteOption } from '../rpc_helpers.js';
8
8
  import { type BackendCapabilities } from './capabilities.js';
9
9
  import type { AppSurfaceSpec } from '../../http/surface.js';
10
10
  import { type FetchTransport } from '../transports/fetch_transport.js';
11
+ import type { SchemaSnapshot } from '../schema_introspect.js';
11
12
  import type { BackendHandle } from './spawn_backend.js';
12
13
  /**
13
14
  * Options for `TestFixture.create_account` — mints an additional
@@ -321,6 +322,21 @@ export interface CrossProcessSetupOptions {
321
322
  */
322
323
  readonly extra_accounts?: ReadonlyArray<ExtraAccountSpec>;
323
324
  }
325
+ /**
326
+ * Capture a backend's schema snapshot over the `_testing_schema_snapshot`
327
+ * RPC action (keeper daemon-token channel). The canonical way for a
328
+ * cross-impl parity gate to read each backend's live schema — pair two
329
+ * calls with `assert_schema_snapshots_equal` (`testing/schema_parity.js`).
330
+ *
331
+ * `exclude_tables` drops documented divergences from both sides before
332
+ * comparison (e.g. a cell-primary Rust backend lacks tables the TS schema
333
+ * has). Each impl answers from its own introspection — TS via
334
+ * `query_schema_snapshot`, Rust via `fuz_db::query_schema_snapshot` — and
335
+ * the snapshot shapes match by design.
336
+ */
337
+ export declare const capture_schema_snapshot: (handle: ReconstructedBootstrappedBackendHandle, options?: {
338
+ exclude_tables?: ReadonlyArray<string>;
339
+ }) => Promise<SchemaSnapshot>;
324
340
  /**
325
341
  * Build a `SetupTest` against a spawned + bootstrapped backend.
326
342
  *
@@ -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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"}
@@ -233,6 +233,22 @@ const rpc_via_transport = async (transport, rpc_path, method, params, backend_na
233
233
  }
234
234
  return raw.result;
235
235
  };
236
+ /**
237
+ * Capture a backend's schema snapshot over the `_testing_schema_snapshot`
238
+ * RPC action (keeper daemon-token channel). The canonical way for a
239
+ * cross-impl parity gate to read each backend's live schema — pair two
240
+ * calls with `assert_schema_snapshots_equal` (`testing/schema_parity.js`).
241
+ *
242
+ * `exclude_tables` drops documented divergences from both sides before
243
+ * comparison (e.g. a cell-primary Rust backend lacks tables the TS schema
244
+ * has). Each impl answers from its own introspection — TS via
245
+ * `query_schema_snapshot`, Rust via `fuz_db::query_schema_snapshot` — and
246
+ * the snapshot shapes match by design.
247
+ */
248
+ export const capture_schema_snapshot = async (handle, options = {}) => {
249
+ const raw = await rpc_via_transport(handle.keeper_transport, handle.config.rpc_path, '_testing_schema_snapshot', { exclude_tables: [...(options.exclude_tables ?? [])] }, handle.config.name, { [DAEMON_TOKEN_HEADER]: handle.daemon_token });
250
+ return raw;
251
+ };
236
252
  /**
237
253
  * Backdating offset (seconds) the `mint_expired_session` seam passes to
238
254
  * `mint_test_session` / `_testing_mint_session`. A minute in the past is
@@ -2,11 +2,12 @@ import '../assert_dev_env.js';
2
2
  /**
3
3
  * Test-binary RPC actions for cross-process integration tests.
4
4
  *
5
- * Three daemon-token-authed actions, bundled by `create_testing_actions`:
5
+ * Four daemon-token-authed actions, bundled by `create_testing_actions`:
6
6
  * **`_testing_reset`** (DB wipe + keeper re-seed), **`_testing_drain_effects`**
7
- * (audit barrier), and **`_testing_mint_session`** (forge an
7
+ * (audit barrier), **`_testing_mint_session`** (forge an
8
8
  * expired-by-construction server-side session for the expiry conformance
9
- * cases).
9
+ * cases), and **`_testing_schema_snapshot`** (introspect the live schema for
10
+ * cross-impl parity diffing against a Rust backend's `fuz_db` snapshot).
10
11
  *
11
12
  * `_testing_reset` — full DB wipe + keeper re-seed + optional
12
13
  * secondary-account seeding. The
@@ -213,6 +214,61 @@ export declare const testing_mint_session_action_spec: {
213
214
  * `create_testing_actions`; in-process suites mount it directly).
214
215
  */
215
216
  export declare const create_testing_drain_effects_action: () => RpcAction;
217
+ /**
218
+ * `_testing_schema_snapshot` — introspect the live database into a normalized
219
+ * `SchemaSnapshot` for cross-impl parity diffing. The cross-backend harness
220
+ * calls this on each backend, then `assert_schema_snapshots_equal`s the
221
+ * results (a Rust backend answers from `fuz_db::query_schema_snapshot`; the
222
+ * shapes match by design). Optional `exclude_tables` drops documented
223
+ * divergences from both sides before comparison.
224
+ *
225
+ * `auth` gates on the daemon-token credential, matching `_testing_reset`.
226
+ */
227
+ export declare const testing_schema_snapshot_action_spec: {
228
+ readonly method: "_testing_schema_snapshot";
229
+ readonly kind: "request_response";
230
+ readonly initiator: "frontend";
231
+ readonly auth: {
232
+ readonly account: "required";
233
+ readonly actor: "none";
234
+ readonly credential_types: readonly ["daemon_token"];
235
+ };
236
+ readonly side_effects: false;
237
+ readonly input: z.ZodObject<{
238
+ exclude_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
239
+ }, z.core.$strict>;
240
+ readonly output: z.ZodObject<{
241
+ tables: z.ZodRecord<z.ZodString, z.ZodObject<{
242
+ columns: z.ZodRecord<z.ZodString, z.ZodObject<{
243
+ data_type: z.ZodString;
244
+ udt_name: z.ZodString;
245
+ is_nullable: z.ZodBoolean;
246
+ column_default: z.ZodNullable<z.ZodString>;
247
+ is_identity: z.ZodBoolean;
248
+ }, z.core.$strip>>;
249
+ indexes: z.ZodArray<z.ZodObject<{
250
+ name: z.ZodString;
251
+ definition: z.ZodString;
252
+ }, z.core.$strip>>;
253
+ constraints: z.ZodArray<z.ZodObject<{
254
+ name: z.ZodString;
255
+ type: z.ZodString;
256
+ definition: z.ZodString;
257
+ }, z.core.$strip>>;
258
+ }, z.core.$strip>>;
259
+ sequences: z.ZodRecord<z.ZodString, z.ZodObject<{
260
+ data_type: z.ZodString;
261
+ }, z.core.$strip>>;
262
+ }, z.core.$strip>;
263
+ readonly async: true;
264
+ readonly description: "Test-binary only — introspect the live schema into a normalized snapshot for cross-impl parity diffing.";
265
+ };
266
+ /**
267
+ * Build the standalone `_testing_schema_snapshot` action. No deps —
268
+ * introspects `ctx.db` via `query_schema_snapshot`. Bundled by
269
+ * `create_testing_actions`; mount directly for in-process use.
270
+ */
271
+ export declare const create_testing_schema_snapshot_action: () => RpcAction;
216
272
  /** Options for `create_testing_actions`. */
217
273
  export interface CreateTestingActionsOptions {
218
274
  /**
@@ -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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyDG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAGtB,OAAO,EAAa,KAAK,SAAS,EAAC,MAAM,6BAA6B,CAAC;AAEvE,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;AAiBvC;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwBQ,CAAC;AAE/C;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,iCAAiC;;;;;;;;;;;;;;;;CAWA,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;CAeC,CAAC;AAE/C;;;;;;GAMG;AACH,eAAO,MAAM,mCAAmC,QAAO,SACiB,CAAC;AAEzE,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,CA0GjB,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAGtB,OAAO,EAAa,KAAK,SAAS,EAAC,MAAM,6BAA6B,CAAC;AAEvE,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;AAkBvC;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwBQ,CAAC;AAE/C;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,iCAAiC;;;;;;;;;;;;;;;;CAWA,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;CAeC,CAAC;AAE/C;;;;;;GAMG;AACH,eAAO,MAAM,mCAAmC,QAAO,SACiB,CAAC;AAEzE;;;;;;;;;GASG;AACH,eAAO,MAAM,mCAAmC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAWF,CAAC;AAE/C;;;;GAIG;AACH,eAAO,MAAM,qCAAqC,QAAO,SAGvD,CAAC;AAEH,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,CA2GjB,CAAC;AAEF,0FAA0F;AAC1F,eAAO,MAAM,0BAA0B,UAAmC,CAAC"}
@@ -2,11 +2,12 @@ import '../assert_dev_env.js';
2
2
  /**
3
3
  * Test-binary RPC actions for cross-process integration tests.
4
4
  *
5
- * Three daemon-token-authed actions, bundled by `create_testing_actions`:
5
+ * Four daemon-token-authed actions, bundled by `create_testing_actions`:
6
6
  * **`_testing_reset`** (DB wipe + keeper re-seed), **`_testing_drain_effects`**
7
- * (audit barrier), and **`_testing_mint_session`** (forge an
7
+ * (audit barrier), **`_testing_mint_session`** (forge an
8
8
  * expired-by-construction server-side session for the expiry conformance
9
- * cases).
9
+ * cases), and **`_testing_schema_snapshot`** (introspect the live schema for
10
+ * cross-impl parity diffing against a Rust backend's `fuz_db` snapshot).
10
11
  *
11
12
  * `_testing_reset` — full DB wipe + keeper re-seed + optional
12
13
  * secondary-account seeding. The
@@ -62,6 +63,7 @@ import { Uuid } from '@fuzdev/fuz_util/id.js';
62
63
  import { rpc_action } from '../../actions/action_rpc.js';
63
64
  import { ROLE_ADMIN, ROLE_KEEPER } from '../../auth/role_schema.js';
64
65
  import { auth_integration_truncate_tables } from '../db.js';
66
+ import { query_schema_snapshot, SchemaSnapshot } from '../schema_introspect.js';
65
67
  import { create_test_account_with_credentials, mint_test_session, DEFAULT_TEST_PASSWORD, } from '../app_server.js';
66
68
  /** Output shape for an individual seeded account (keeper or extra). */
67
69
  const SeededAccountShape = z.strictObject({
@@ -188,6 +190,33 @@ export const testing_mint_session_action_spec = {
188
190
  * `create_testing_actions`; in-process suites mount it directly).
189
191
  */
190
192
  export const create_testing_drain_effects_action = () => rpc_action(testing_drain_effects_action_spec, async () => ({ ok: true }));
193
+ /**
194
+ * `_testing_schema_snapshot` — introspect the live database into a normalized
195
+ * `SchemaSnapshot` for cross-impl parity diffing. The cross-backend harness
196
+ * calls this on each backend, then `assert_schema_snapshots_equal`s the
197
+ * results (a Rust backend answers from `fuz_db::query_schema_snapshot`; the
198
+ * shapes match by design). Optional `exclude_tables` drops documented
199
+ * divergences from both sides before comparison.
200
+ *
201
+ * `auth` gates on the daemon-token credential, matching `_testing_reset`.
202
+ */
203
+ export const testing_schema_snapshot_action_spec = {
204
+ method: '_testing_schema_snapshot',
205
+ kind: 'request_response',
206
+ initiator: 'frontend',
207
+ auth: { account: 'required', actor: 'none', credential_types: ['daemon_token'] },
208
+ side_effects: false,
209
+ input: z.strictObject({ exclude_tables: z.array(z.string()).optional() }),
210
+ output: SchemaSnapshot,
211
+ async: true,
212
+ description: 'Test-binary only — introspect the live schema into a normalized snapshot for cross-impl parity diffing.',
213
+ };
214
+ /**
215
+ * Build the standalone `_testing_schema_snapshot` action. No deps —
216
+ * introspects `ctx.db` via `query_schema_snapshot`. Bundled by
217
+ * `create_testing_actions`; mount directly for in-process use.
218
+ */
219
+ 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 }));
191
220
  /**
192
221
  * Build the testing RPC actions for a test binary's registry.
193
222
  *
@@ -298,6 +327,7 @@ export const create_testing_actions = (deps, options) => {
298
327
  return { session_cookie };
299
328
  }),
300
329
  create_testing_drain_effects_action(),
330
+ create_testing_schema_snapshot_action(),
301
331
  ];
302
332
  };
303
333
  /** Set of auth-namespace tables `_testing_reset` wipes. Mirrored by the coverage test. */
@@ -5,8 +5,6 @@ import './assert_dev_env.js';
5
5
  *
6
6
  * The snapshot covers:
7
7
  *
8
- * - `schema_version` rows (`namespace`, `name`, `sequence`) — captures
9
- * migration set state across impls
10
8
  * - Tables with columns (data type, nullability, default, identity)
11
9
  * - Indexes with canonical Postgres-rendered definitions
12
10
  * - Constraints (CHECK, FOREIGN KEY, PRIMARY KEY, UNIQUE, EXCLUSION)
@@ -21,60 +19,80 @@ import './assert_dev_env.js';
21
19
  *
22
20
  * @module
23
21
  */
22
+ import { z } from 'zod';
24
23
  import type { Db } from '../db/db.js';
25
- /** Per-column structural metadata. */
26
- export interface ColumnSnapshot {
27
- /** SQL standard type name from `information_schema.columns.data_type`. */
28
- readonly data_type: string;
29
- /** Postgres-native type name from `information_schema.columns.udt_name`. */
30
- readonly udt_name: string;
31
- /** `true` when the column accepts NULL. */
32
- readonly is_nullable: boolean;
33
- /** Default-value expression as Postgres reports it, or `null` if none. */
34
- readonly column_default: string | null;
35
- /** `true` when the column was declared GENERATED ... AS IDENTITY. */
36
- readonly is_identity: boolean;
37
- }
24
+ /**
25
+ * Per-column structural metadata. The Zod schema is the canonical source
26
+ * for the column shape `SchemaSnapshot` reuses it as the cross-impl
27
+ * `_testing_schema_snapshot` RPC action's wire validator, so the
28
+ * introspection type and the wire contract can't drift apart.
29
+ */
30
+ export declare const ColumnSnapshot: z.ZodObject<{
31
+ data_type: z.ZodString;
32
+ udt_name: z.ZodString;
33
+ is_nullable: z.ZodBoolean;
34
+ column_default: z.ZodNullable<z.ZodString>;
35
+ is_identity: z.ZodBoolean;
36
+ }, z.core.$strip>;
37
+ export type ColumnSnapshot = z.infer<typeof ColumnSnapshot>;
38
38
  /** Per-table structural metadata. */
39
- export interface TableSnapshot {
40
- /** Column metadata keyed by column name (sorted on serialization). */
41
- readonly columns: Record<string, ColumnSnapshot>;
42
- /** Index definitions as Postgres renders them via `pg_indexes.indexdef`. */
43
- readonly indexes: ReadonlyArray<{
44
- readonly name: string;
45
- readonly definition: string;
46
- }>;
47
- /** Constraint definitions as Postgres renders them via `pg_get_constraintdef`. */
48
- readonly constraints: ReadonlyArray<{
49
- readonly name: string;
50
- readonly type: string;
51
- readonly definition: string;
52
- }>;
53
- }
39
+ export declare const TableSnapshot: z.ZodObject<{
40
+ columns: z.ZodRecord<z.ZodString, z.ZodObject<{
41
+ data_type: z.ZodString;
42
+ udt_name: z.ZodString;
43
+ is_nullable: z.ZodBoolean;
44
+ column_default: z.ZodNullable<z.ZodString>;
45
+ is_identity: z.ZodBoolean;
46
+ }, z.core.$strip>>;
47
+ indexes: z.ZodArray<z.ZodObject<{
48
+ name: z.ZodString;
49
+ definition: z.ZodString;
50
+ }, z.core.$strip>>;
51
+ constraints: z.ZodArray<z.ZodObject<{
52
+ name: z.ZodString;
53
+ type: z.ZodString;
54
+ definition: z.ZodString;
55
+ }, z.core.$strip>>;
56
+ }, z.core.$strip>;
57
+ export type TableSnapshot = z.infer<typeof TableSnapshot>;
54
58
  /** Sequence metadata — `data_type` is `bigint` (BIGSERIAL) or `integer` (SERIAL). */
55
- export interface SequenceSnapshot {
56
- readonly data_type: string;
57
- }
58
- /** One row in the `schema_version` migration tracker. */
59
- export interface SchemaVersionRow {
60
- readonly namespace: string;
61
- readonly name: string;
62
- readonly sequence: number;
63
- }
59
+ export declare const SequenceSnapshot: z.ZodObject<{
60
+ data_type: z.ZodString;
61
+ }, z.core.$strip>;
62
+ export type SequenceSnapshot = z.infer<typeof SequenceSnapshot>;
64
63
  /**
65
- * Normalized database schema snapshot for parity comparison.
64
+ * Normalized database schema snapshot for parity comparison — the single
65
+ * source of truth for the snapshot shape across the introspection query
66
+ * (`query_schema_snapshot`), the diff comparator (`schema_parity.ts`), and
67
+ * the cross-impl RPC action's wire validator (`testing_reset_actions.ts`).
66
68
  *
67
69
  * All fields are deterministically ordered on capture so structural equality
68
70
  * via `JSON.stringify` or per-key comparison yields stable results.
69
71
  */
70
- export interface SchemaSnapshot {
71
- /** Migration tracker rows, sorted by `(namespace, sequence)`. */
72
- readonly schema_version: ReadonlyArray<SchemaVersionRow>;
73
- /** Tables keyed by name. */
74
- readonly tables: Record<string, TableSnapshot>;
75
- /** Sequences keyed by name. */
76
- readonly sequences: Record<string, SequenceSnapshot>;
77
- }
72
+ export declare const SchemaSnapshot: z.ZodObject<{
73
+ tables: z.ZodRecord<z.ZodString, z.ZodObject<{
74
+ columns: z.ZodRecord<z.ZodString, z.ZodObject<{
75
+ data_type: z.ZodString;
76
+ udt_name: z.ZodString;
77
+ is_nullable: z.ZodBoolean;
78
+ column_default: z.ZodNullable<z.ZodString>;
79
+ is_identity: z.ZodBoolean;
80
+ }, z.core.$strip>>;
81
+ indexes: z.ZodArray<z.ZodObject<{
82
+ name: z.ZodString;
83
+ definition: z.ZodString;
84
+ }, z.core.$strip>>;
85
+ constraints: z.ZodArray<z.ZodObject<{
86
+ name: z.ZodString;
87
+ type: z.ZodString;
88
+ definition: z.ZodString;
89
+ }, z.core.$strip>>;
90
+ }, z.core.$strip>>;
91
+ sequences: z.ZodRecord<z.ZodString, z.ZodObject<{
92
+ data_type: z.ZodString;
93
+ }, z.core.$strip>>;
94
+ }, z.core.$strip>;
95
+ export type SchemaSnapshot = z.infer<typeof SchemaSnapshot>;
78
96
  /** Filter options for `query_schema_snapshot`. */
79
97
  export interface QuerySchemaSnapshotOptions {
80
98
  /**
@@ -83,8 +101,10 @@ export interface QuerySchemaSnapshotOptions {
83
101
  */
84
102
  readonly schema?: string;
85
103
  /**
86
- * Tables to exclude from the snapshot. The `schema_version` table itself
87
- * is always excluded (its content is captured separately).
104
+ * Tables to exclude from the snapshot. The `schema_version` migration
105
+ * tracker is always excluded it's framework bookkeeping created by the
106
+ * migration runner, identical across impls, and not part of any
107
+ * consumer's domain schema.
88
108
  */
89
109
  readonly exclude_tables?: ReadonlyArray<string>;
90
110
  }
@@ -92,15 +112,11 @@ export interface QuerySchemaSnapshotOptions {
92
112
  * Introspect a live database into a deterministic `SchemaSnapshot`.
93
113
  *
94
114
  * Reads `information_schema` and `pg_catalog` to capture tables, columns,
95
- * indexes, constraints, sequences, and `schema_version` migration tracker
96
- * rows. The `applied_at` timestamp is deliberately excluded — only the set
97
- * of applied migrations matters for parity.
98
- *
99
- * The `schema_version` table itself never appears in the `tables` field;
100
- * its structure is identical across consumers and would only add noise.
115
+ * indexes, constraints, and sequences.
101
116
  *
102
- * @throws Error when the `schema_version` table is missing callers must
103
- * ensure migrations have run before introspecting.
117
+ * The `schema_version` migration tracker never appears in the `tables`
118
+ * field it's framework bookkeeping created by the migration runner,
119
+ * identical across consumers, and would only add noise.
104
120
  */
105
121
  export declare const query_schema_snapshot: (db: Db, options?: QuerySchemaSnapshotOptions) => Promise<SchemaSnapshot>;
106
122
  //# sourceMappingURL=schema_introspect.d.ts.map
@@ -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;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAC,EAAE,EAAC,MAAM,aAAa,CAAC;AAEpC,sCAAsC;AACtC,MAAM,WAAW,cAAc;IAC9B,0EAA0E;IAC1E,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,4EAA4E;IAC5E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,2CAA2C;IAC3C,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B,0EAA0E;IAC1E,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,qEAAqE;IACrE,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;CAC9B;AAED,qCAAqC;AACrC,MAAM,WAAW,aAAa;IAC7B,sEAAsE;IACtE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IACjD,4EAA4E;IAC5E,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;KAAC,CAAC,CAAC;IACtF,kFAAkF;IAClF,QAAQ,CAAC,WAAW,EAAE,aAAa,CAAC;QACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;KAC5B,CAAC,CAAC;CACH;AAED,qFAAqF;AACrF,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC3B;AAED,yDAAyD;AACzD,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC9B,iEAAiE;IACjE,QAAQ,CAAC,cAAc,EAAE,aAAa,CAAC,gBAAgB,CAAC,CAAC;IACzD,4BAA4B;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC/C,+BAA+B;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;CACrD;AAED,kDAAkD;AAClD,MAAM,WAAW,0BAA0B;IAC1C;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CAChD;AAyDD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,qBAAqB,GACjC,IAAI,EAAE,EACN,UAAS,0BAA+B,KACtC,OAAO,CAAC,cAAc,CA+GxB,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;;;;;;;;;;;;;;;;;;;GAmBG;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;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;iBAKzB,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;AAyDD;;;;;;;;;GASG;AACH,eAAO,MAAM,qBAAqB,GACjC,IAAI,EAAE,EACN,UAAS,0BAA+B,KACtC,OAAO,CAAC,cAAc,CAuGxB,CAAC"}
@@ -1,4 +1,71 @@
1
1
  import './assert_dev_env.js';
2
+ /**
3
+ * PostgreSQL schema introspection — produces a normalized, JSON-serializable
4
+ * snapshot of a database's structure for cross-impl parity checks.
5
+ *
6
+ * The snapshot covers:
7
+ *
8
+ * - Tables with columns (data type, nullability, default, identity)
9
+ * - Indexes with canonical Postgres-rendered definitions
10
+ * - Constraints (CHECK, FOREIGN KEY, PRIMARY KEY, UNIQUE, EXCLUSION)
11
+ * - Sequences with data type — distinguishes `int4` (SERIAL) from `int8`
12
+ * (BIGSERIAL)
13
+ *
14
+ * Designed for `pg_catalog` introspection — works against both PostgreSQL
15
+ * and PGlite. The snapshot is fully deterministic: every collection sorts by
16
+ * a stable key and excludes time-varying fields like `applied_at`.
17
+ *
18
+ * Paired with `schema_parity.ts` for comparison + assertion helpers.
19
+ *
20
+ * @module
21
+ */
22
+ import { z } from 'zod';
23
+ /**
24
+ * Per-column structural metadata. The Zod schema is the canonical source
25
+ * for the column shape — `SchemaSnapshot` reuses it as the cross-impl
26
+ * `_testing_schema_snapshot` RPC action's wire validator, so the
27
+ * introspection type and the wire contract can't drift apart.
28
+ */
29
+ export const ColumnSnapshot = z.object({
30
+ /** SQL standard type name from `information_schema.columns.data_type`. */
31
+ data_type: z.string(),
32
+ /** Postgres-native type name from `information_schema.columns.udt_name`. */
33
+ udt_name: z.string(),
34
+ /** `true` when the column accepts NULL. */
35
+ is_nullable: z.boolean(),
36
+ /** Default-value expression as Postgres reports it, or `null` if none. */
37
+ column_default: z.string().nullable(),
38
+ /** `true` when the column was declared GENERATED ... AS IDENTITY. */
39
+ is_identity: z.boolean(),
40
+ });
41
+ /** Per-table structural metadata. */
42
+ export const TableSnapshot = z.object({
43
+ /** Column metadata keyed by column name (sorted on serialization). */
44
+ columns: z.record(z.string(), ColumnSnapshot),
45
+ /** Index definitions as Postgres renders them via `pg_indexes.indexdef`. */
46
+ indexes: z.array(z.object({ name: z.string(), definition: z.string() })),
47
+ /** Constraint definitions as Postgres renders them via `pg_get_constraintdef`. */
48
+ constraints: z.array(z.object({ name: z.string(), type: z.string(), definition: z.string() })),
49
+ });
50
+ /** Sequence metadata — `data_type` is `bigint` (BIGSERIAL) or `integer` (SERIAL). */
51
+ export const SequenceSnapshot = z.object({
52
+ data_type: z.string(),
53
+ });
54
+ /**
55
+ * Normalized database schema snapshot for parity comparison — the single
56
+ * source of truth for the snapshot shape across the introspection query
57
+ * (`query_schema_snapshot`), the diff comparator (`schema_parity.ts`), and
58
+ * the cross-impl RPC action's wire validator (`testing_reset_actions.ts`).
59
+ *
60
+ * All fields are deterministically ordered on capture so structural equality
61
+ * via `JSON.stringify` or per-key comparison yields stable results.
62
+ */
63
+ export const SchemaSnapshot = z.object({
64
+ /** Tables keyed by name. */
65
+ tables: z.record(z.string(), TableSnapshot),
66
+ /** Sequences keyed by name. */
67
+ sequences: z.record(z.string(), SequenceSnapshot),
68
+ });
2
69
  const sort_keys = (record) => {
3
70
  const sorted = {};
4
71
  for (const key of Object.keys(record).sort()) {
@@ -28,26 +95,16 @@ const contype_to_kind = (contype) => {
28
95
  * Introspect a live database into a deterministic `SchemaSnapshot`.
29
96
  *
30
97
  * Reads `information_schema` and `pg_catalog` to capture tables, columns,
31
- * indexes, constraints, sequences, and `schema_version` migration tracker
32
- * rows. The `applied_at` timestamp is deliberately excluded — only the set
33
- * of applied migrations matters for parity.
34
- *
35
- * The `schema_version` table itself never appears in the `tables` field;
36
- * its structure is identical across consumers and would only add noise.
98
+ * indexes, constraints, and sequences.
37
99
  *
38
- * @throws Error when the `schema_version` table is missing callers must
39
- * ensure migrations have run before introspecting.
100
+ * The `schema_version` migration tracker never appears in the `tables`
101
+ * field it's framework bookkeeping created by the migration runner,
102
+ * identical across consumers, and would only add noise.
40
103
  */
41
104
  export const query_schema_snapshot = async (db, options = {}) => {
42
105
  const schema = options.schema ?? 'public';
43
106
  const exclude_tables = new Set(options.exclude_tables ?? []);
44
107
  exclude_tables.add('schema_version');
45
- // schema_version rows — the migration tracker. Exclude `applied_at`
46
- // because timestamps differ across bootstraps even when the migration
47
- // set is identical.
48
- const schema_version_rows = await db.query(`SELECT namespace, name, sequence
49
- FROM schema_version
50
- ORDER BY namespace ASC, sequence ASC`);
51
108
  // All tables in the target schema, minus the excludes.
52
109
  const table_rows = await db.query(`SELECT table_name
53
110
  FROM information_schema.tables
@@ -68,6 +125,11 @@ export const query_schema_snapshot = async (db, options = {}) => {
68
125
  WHERE schemaname = $1
69
126
  ORDER BY tablename ASC, indexname ASC`, [schema]);
70
127
  // Constraints — pg_get_constraintdef produces a canonical text rendering.
128
+ // Skip NOT NULL constraints (`contype = 'n'`): PG17+ catalogs them as
129
+ // named `pg_constraint` rows while PGlite / older PG don't, and
130
+ // nullability is already captured per-column by `is_nullable` — including
131
+ // them would report a pure engine-cataloging artifact as cross-backend
132
+ // drift between a PGlite and a real-Postgres backend.
71
133
  const constraint_rows = await db.query(`SELECT c.conrelid::regclass::text AS table_name,
72
134
  c.conname,
73
135
  c.contype::text,
@@ -76,6 +138,7 @@ export const query_schema_snapshot = async (db, options = {}) => {
76
138
  JOIN pg_namespace n ON n.oid = c.connamespace
77
139
  WHERE n.nspname = $1
78
140
  AND c.conrelid != 0
141
+ AND c.contype != 'n'
79
142
  ORDER BY table_name ASC, conname ASC`, [schema]);
80
143
  // Sequences — data_type distinguishes bigint (BIGSERIAL) from integer (SERIAL).
81
144
  const sequence_rows = await db.query(`SELECT sequence_name, data_type
@@ -116,7 +179,6 @@ export const query_schema_snapshot = async (db, options = {}) => {
116
179
  sequences[row.sequence_name] = { data_type: row.data_type };
117
180
  }
118
181
  return {
119
- schema_version: schema_version_rows,
120
182
  tables: sort_keys(tables),
121
183
  sequences: sort_keys(sequences),
122
184
  };
@@ -6,7 +6,7 @@ import './assert_dev_env.js';
6
6
  * Two live impls (TS fuz_app vs Rust spine) are each other's parity
7
7
  * reference. After both bootstrap, snapshot each, diff, fail loudly on
8
8
  * drift. The diff entries name the specific divergence (column type,
9
- * missing index, schema_version row absent on one side) so the error
9
+ * missing index, constraint absent on one side) so the error
10
10
  * message points at the source.
11
11
  *
12
12
  * Consumer pattern (in zzz's integration runner or fuz_app's own
@@ -29,8 +29,8 @@ import './assert_dev_env.js';
29
29
  * impls with the same columns in different declaration order compare
30
30
  * equal (functional parity is preserved; `SELECT *` ordering is not)
31
31
  * - `COMMENT ON ...`
32
- * - the `schema_version` table's own structure (only its rows are
33
- * captured)
32
+ * - the `schema_version` migration tracker (always excluded framework
33
+ * bookkeeping, not domain schema)
34
34
  * - permissions / `GRANT`s
35
35
  *
36
36
  * None of these are used by the current fuz_app auth schema. Extend
@@ -40,19 +40,9 @@ import './assert_dev_env.js';
40
40
  *
41
41
  * @module
42
42
  */
43
- import type { ColumnSnapshot, SchemaSnapshot, SchemaVersionRow } from './schema_introspect.js';
43
+ import type { ColumnSnapshot, SchemaSnapshot } from './schema_introspect.js';
44
44
  /** Structured drift entry. `where` is the named source impl ('a' or 'b'). */
45
45
  export type SchemaDiff = {
46
- readonly kind: 'schema_version_only_in';
47
- readonly where: 'a' | 'b';
48
- readonly row: SchemaVersionRow;
49
- } | {
50
- readonly kind: 'schema_version_sequence_differs';
51
- readonly namespace: string;
52
- readonly name: string;
53
- readonly a: number;
54
- readonly b: number;
55
- } | {
56
46
  readonly kind: 'table_only_in';
57
47
  readonly where: 'a' | 'b';
58
48
  readonly table: string;
@@ -109,9 +99,9 @@ export type SchemaDiff = {
109
99
  /**
110
100
  * Structural diff between two snapshots — empty array means parity holds.
111
101
  *
112
- * Order of diffs is deterministic: schema_version first, then tables in
113
- * sorted order (with column/index/constraint sub-diffs grouped per table),
114
- * then sequences. Consumers can rely on this for stable diff output.
102
+ * Order of diffs is deterministic: tables in sorted order (with
103
+ * column/index/constraint sub-diffs grouped per table), then sequences.
104
+ * Consumers can rely on this for stable diff output.
115
105
  */
116
106
  export declare const diff_schema_snapshots: (a: SchemaSnapshot, b: SchemaSnapshot) => Array<SchemaDiff>;
117
107
  /** Labels used in formatted output — defaults to `'a'` and `'b'`. */
@@ -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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"}
@@ -2,13 +2,12 @@ import './assert_dev_env.js';
2
2
  /**
3
3
  * Structural diff between two snapshots — empty array means parity holds.
4
4
  *
5
- * Order of diffs is deterministic: schema_version first, then tables in
6
- * sorted order (with column/index/constraint sub-diffs grouped per table),
7
- * then sequences. Consumers can rely on this for stable diff output.
5
+ * Order of diffs is deterministic: tables in sorted order (with
6
+ * column/index/constraint sub-diffs grouped per table), then sequences.
7
+ * Consumers can rely on this for stable diff output.
8
8
  */
9
9
  export const diff_schema_snapshots = (a, b) => {
10
10
  const diffs = [];
11
- diff_schema_version(a.schema_version, b.schema_version, diffs);
12
11
  const all_tables = new Set([...Object.keys(a.tables), ...Object.keys(b.tables)]);
13
12
  for (const table of [...all_tables].sort()) {
14
13
  const ta = a.tables[table];
@@ -39,33 +38,6 @@ export const diff_schema_snapshots = (a, b) => {
39
38
  }
40
39
  return diffs;
41
40
  };
42
- const diff_schema_version = (a, b, out) => {
43
- const key = (r) => `${r.namespace}\x00${r.name}`;
44
- const a_by_key = new Map(a.map((r) => [key(r), r]));
45
- const b_by_key = new Map(b.map((r) => [key(r), r]));
46
- const keys = new Set([...a_by_key.keys(), ...b_by_key.keys()]);
47
- for (const k of [...keys].sort()) {
48
- const row_a = a_by_key.get(k);
49
- const row_b = b_by_key.get(k);
50
- if (!row_a) {
51
- out.push({ kind: 'schema_version_only_in', where: 'b', row: row_b });
52
- continue;
53
- }
54
- if (!row_b) {
55
- out.push({ kind: 'schema_version_only_in', where: 'a', row: row_a });
56
- continue;
57
- }
58
- if (row_a.sequence !== row_b.sequence) {
59
- out.push({
60
- kind: 'schema_version_sequence_differs',
61
- namespace: row_a.namespace,
62
- name: row_a.name,
63
- a: row_a.sequence,
64
- b: row_b.sequence,
65
- });
66
- }
67
- }
68
- };
69
41
  const COLUMN_FIELDS = [
70
42
  'data_type',
71
43
  'udt_name',
@@ -165,12 +137,6 @@ export const format_schema_diffs = (diffs, labels = {}) => {
165
137
  const lines = [];
166
138
  for (const d of diffs) {
167
139
  switch (d.kind) {
168
- case 'schema_version_only_in':
169
- lines.push(` schema_version row only in ${where_label(d.where)}: ${d.row.namespace}/${d.row.name} (sequence ${d.row.sequence})`);
170
- break;
171
- case 'schema_version_sequence_differs':
172
- lines.push(` schema_version sequence differs for ${d.namespace}/${d.name}: ${label_a}=${d.a}, ${label_b}=${d.b}`);
173
- break;
174
140
  case 'table_only_in':
175
141
  lines.push(` table ${d.table} only in ${where_label(d.where)}`);
176
142
  break;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fuzdev/fuz_app",
3
- "version": "0.70.0",
3
+ "version": "0.71.0",
4
4
  "description": "fullstack app library",
5
5
  "glyph": "🗝",
6
6
  "logo": "logo.svg",