@substrat-run/contract-tests 0.139.0 → 0.140.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.
Files changed (90) hide show
  1. package/dist/capability-suite.d.ts.map +1 -1
  2. package/dist/capability-suite.js +5 -0
  3. package/dist/capability-suite.js.map +1 -1
  4. package/dist/caused-by-suite.d.ts.map +1 -1
  5. package/dist/caused-by-suite.js +54 -10
  6. package/dist/caused-by-suite.js.map +1 -1
  7. package/dist/connect-link-suite.d.ts +19 -0
  8. package/dist/connect-link-suite.d.ts.map +1 -0
  9. package/dist/connect-link-suite.js +215 -0
  10. package/dist/connect-link-suite.js.map +1 -0
  11. package/dist/entity-state-migration-suite.d.ts +16 -0
  12. package/dist/entity-state-migration-suite.d.ts.map +1 -0
  13. package/dist/entity-state-migration-suite.js +305 -0
  14. package/dist/entity-state-migration-suite.js.map +1 -0
  15. package/dist/entity-state-module.d.ts +183 -0
  16. package/dist/entity-state-module.d.ts.map +1 -1
  17. package/dist/entity-state-module.js +139 -1
  18. package/dist/entity-state-module.js.map +1 -1
  19. package/dist/entity-state-suite.d.ts.map +1 -1
  20. package/dist/entity-state-suite.js +35 -12
  21. package/dist/entity-state-suite.js.map +1 -1
  22. package/dist/entity-trash-module.d.ts +439 -0
  23. package/dist/entity-trash-module.d.ts.map +1 -0
  24. package/dist/entity-trash-module.js +287 -0
  25. package/dist/entity-trash-module.js.map +1 -0
  26. package/dist/entity-trash-suite.d.ts +59 -0
  27. package/dist/entity-trash-suite.d.ts.map +1 -0
  28. package/dist/entity-trash-suite.js +568 -0
  29. package/dist/entity-trash-suite.js.map +1 -0
  30. package/dist/erasure-module.d.ts +259 -0
  31. package/dist/erasure-module.d.ts.map +1 -0
  32. package/dist/erasure-module.js +251 -0
  33. package/dist/erasure-module.js.map +1 -0
  34. package/dist/index.d.ts +13 -1
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +13 -1
  37. package/dist/index.js.map +1 -1
  38. package/dist/list-suite.d.ts.map +1 -1
  39. package/dist/list-suite.js +101 -1
  40. package/dist/list-suite.js.map +1 -1
  41. package/dist/membership-executor-suite.d.ts.map +1 -1
  42. package/dist/membership-executor-suite.js +60 -9
  43. package/dist/membership-executor-suite.js.map +1 -1
  44. package/dist/migration-comments-suite.d.ts +3 -0
  45. package/dist/migration-comments-suite.d.ts.map +1 -0
  46. package/dist/migration-comments-suite.js +92 -0
  47. package/dist/migration-comments-suite.js.map +1 -0
  48. package/dist/migration-comments.d.ts +3 -0
  49. package/dist/migration-comments.d.ts.map +1 -0
  50. package/dist/migration-comments.js +50 -0
  51. package/dist/migration-comments.js.map +1 -0
  52. package/dist/migration-digest-suite.d.ts +3 -0
  53. package/dist/migration-digest-suite.d.ts.map +1 -0
  54. package/dist/migration-digest-suite.js +175 -0
  55. package/dist/migration-digest-suite.js.map +1 -0
  56. package/dist/modules.d.ts +542 -0
  57. package/dist/modules.d.ts.map +1 -1
  58. package/dist/modules.js +155 -7
  59. package/dist/modules.js.map +1 -1
  60. package/dist/peer-suite.d.ts +2 -1
  61. package/dist/peer-suite.d.ts.map +1 -1
  62. package/dist/peer-suite.js +103 -1
  63. package/dist/peer-suite.js.map +1 -1
  64. package/dist/permission-suite.d.ts.map +1 -1
  65. package/dist/permission-suite.js +515 -2
  66. package/dist/permission-suite.js.map +1 -1
  67. package/dist/scope-host-suite.d.ts.map +1 -1
  68. package/dist/scope-host-suite.js +54 -1
  69. package/dist/scope-host-suite.js.map +1 -1
  70. package/dist/split-cases.d.ts +12 -0
  71. package/dist/split-cases.d.ts.map +1 -0
  72. package/dist/split-cases.js +59 -0
  73. package/dist/split-cases.js.map +1 -0
  74. package/dist/subject-erasure-suite.d.ts +6 -0
  75. package/dist/subject-erasure-suite.d.ts.map +1 -0
  76. package/dist/subject-erasure-suite.js +287 -0
  77. package/dist/subject-erasure-suite.js.map +1 -0
  78. package/dist/switch-audit-fault.d.ts +48 -0
  79. package/dist/switch-audit-fault.d.ts.map +1 -0
  80. package/dist/switch-audit-fault.js +80 -0
  81. package/dist/switch-audit-fault.js.map +1 -0
  82. package/dist/system-switch-suite.d.ts +2 -1
  83. package/dist/system-switch-suite.d.ts.map +1 -1
  84. package/dist/system-switch-suite.js +90 -0
  85. package/dist/system-switch-suite.js.map +1 -1
  86. package/dist/vertical-events-suite.d.ts +41 -0
  87. package/dist/vertical-events-suite.d.ts.map +1 -1
  88. package/dist/vertical-events-suite.js +55 -0
  89. package/dist/vertical-events-suite.js.map +1 -1
  90. package/package.json +3 -3
@@ -0,0 +1,175 @@
1
+ /**
2
+ * Contract suite for the SQL digest a scope's migration journal records (#2066).
3
+ *
4
+ * A scope used to journal an applied migration by `(module_id, version)` alone, so a later
5
+ * migration with the same version and different SQL was skipped as already applied and the
6
+ * scope kept whichever schema it got first. Both adapters now record the SHA-256 of the exact
7
+ * SQL beside the version, and hold an authored migration to it.
8
+ *
9
+ * A scope that "ran different SQL" is made the way an operator would meet one: its own dump,
10
+ * with the journal's digest edited, restored onto it. That is an adapter-neutral door, and a
11
+ * restore refreshes what the host believes was applied, so the next pass reads the edited row.
12
+ *
13
+ * `listMod` because it carries both kinds of migration: two authored versions and the
14
+ * kernel-derived list index, which is versioned by its declaration and not held to a digest.
15
+ */
16
+ import { describe, it, expect, beforeAll, afterAll } from 'vitest';
17
+ import { platformActorId, principalId, scopeId, tenantId } from '@substrat-run/contracts';
18
+ import { moduleMigrations, ulid } from '@substrat-run/kernel';
19
+ import { listMod } from './modules.js';
20
+ const MODULE = '@test/list';
21
+ /** `_substrat_migrations` as `sqlite_master` held it before #2066 — what a pre-digest dump carries. */
22
+ const PRE_DIGEST_JOURNAL_DDL = `CREATE TABLE _substrat_migrations (
23
+ module_id TEXT NOT NULL,
24
+ version TEXT NOT NULL,
25
+ applied_at TEXT NOT NULL,
26
+ duration_ms INTEGER,
27
+ rows_changed INTEGER,
28
+ PRIMARY KEY (module_id, version)
29
+ )`;
30
+ const AUTHORED = '0001-init';
31
+ /** SHA-256 hex, computed here with Web Crypto rather than through the kernel helper under test. */
32
+ const sha256 = async (text) => [...new Uint8Array(await crypto.subtle.digest('SHA-256', new TextEncoder().encode(text)))]
33
+ .map((b) => b.toString(16).padStart(2, '0'))
34
+ .join('');
35
+ export function migrationDigestContractSuite(adapterName, makeFixture) {
36
+ describe(`migration SQL digests (#2066): ${adapterName}`, () => {
37
+ let fixture;
38
+ let host;
39
+ const t = tenantId.parse(ulid());
40
+ const s = scopeId.parse(ulid());
41
+ const staff = platformActorId.parse(ulid());
42
+ const alice = principalId.parse(ulid());
43
+ /** The scope's own dump, taken once it has migrated — what every case restores from. */
44
+ let clean;
45
+ /** The registered SQL's digest per version, derived set included. */
46
+ let expected;
47
+ const add = async () => (await host.getScope(alice, t, s)).invoke('list/add', { id: ulid(), number: ulid(), status: 'open', kind: 'a' });
48
+ /** This module's journal rows in a dump: version → { digest, appliedAt }. */
49
+ const journalOf = (dump) => {
50
+ const table = dump.tables.find((tbl) => tbl.name === '_substrat_migrations');
51
+ const col = (name) => table.columns.indexOf(name);
52
+ return new Map(table.rows
53
+ .filter((r) => r[col('module_id')] === MODULE)
54
+ .map((r) => [String(r[col('version')]), { digest: r[col('sql_digest')] ?? null, appliedAt: r[col('applied_at')] }]));
55
+ };
56
+ const journal = async () => journalOf(await host.admin.exportScope(staff, t, s));
57
+ /** `clean`, with this module's journal digest rewritten for the versions `edit` names. */
58
+ const restoreWith = async (edit) => {
59
+ const tables = clean.tables.map((tbl) => {
60
+ if (tbl.name !== '_substrat_migrations')
61
+ return tbl;
62
+ const col = (name) => tbl.columns.indexOf(name);
63
+ return {
64
+ ...tbl,
65
+ rows: tbl.rows.map((r) => {
66
+ const version = String(r[col('version')]);
67
+ if (r[col('module_id')] !== MODULE || !(version in edit))
68
+ return r;
69
+ const row = [...r];
70
+ row[col('sql_digest')] = edit[version] ?? null;
71
+ return row;
72
+ }),
73
+ };
74
+ });
75
+ await host.restoreScope(staff, t, s, { ...clean, tables });
76
+ };
77
+ beforeAll(async () => {
78
+ fixture = await makeFixture();
79
+ host = fixture.host;
80
+ host.registerModule(listMod);
81
+ await host.admin.createTenant(staff, { id: t, slug: `digest-${ulid().toLowerCase()}`, name: 'Digest' });
82
+ await host.admin.grantEntitlement(staff, t, 'list');
83
+ await host.provisionScope(staff, { tenantId: t, scopeId: s, vertical: 'list-vertical' });
84
+ await host.admin.activateScope(staff, t, s);
85
+ await add();
86
+ clean = await host.admin.exportScope(staff, t, s);
87
+ expected = new Map(await Promise.all(moduleMigrations(listMod).map(async (m) => [m.version, await sha256(m.sql)])));
88
+ });
89
+ afterAll(async () => {
90
+ await fixture?.cleanup();
91
+ });
92
+ it("a fresh scope records the SHA-256 of each migration's exact SQL, derived DDL included", async () => {
93
+ // Three: the two authored versions and the kernel's list index, so neither kind is vacuous.
94
+ expect([...expected.keys()]).toEqual(['0001-init', '0002-hold', expect.stringMatching(/^list\//)]);
95
+ const rows = journalOf(clean);
96
+ expect(new Map([...rows].map(([v, r]) => [v, r.digest]))).toEqual(expected);
97
+ });
98
+ it('the same digest is skipped: nothing re-runs, and the scope serves', async () => {
99
+ const before = await journal();
100
+ await restoreWith({});
101
+ await expect(add()).resolves.toBeDefined();
102
+ // Not re-applied: the rows are the ones the first pass wrote, applied_at and all.
103
+ expect(await journal()).toEqual(before);
104
+ expect((await host.migrateScope(t, s)).status).not.toBe('failed');
105
+ });
106
+ it('a different digest fails the scope closed, naming the module, the version and both digests', async () => {
107
+ const ran = await sha256('CREATE TABLE list_orders (id TEXT PRIMARY KEY);');
108
+ const registered = expected.get(AUTHORED);
109
+ await restoreWith({ [AUTHORED]: ran });
110
+ const named = new RegExp(`migration failed for ${MODULE}@${AUTHORED} — scope fails closed: .*applied sha256 ${ran}, registered sha256 ${registered}`);
111
+ await expect(add()).rejects.toThrow(named);
112
+ // The sweep's door says the same, as the structured failure a failed migration leaves.
113
+ const outcome = await host.migrateScope(t, s);
114
+ expect(outcome).toEqual({ status: 'failed', failure: { version: `${MODULE}@${AUTHORED}`, error: expect.any(String) } });
115
+ const failure = outcome.failure;
116
+ expect(failure.error).toContain(ran);
117
+ expect(failure.error).toContain(registered);
118
+ // Recovery: the scope's journal agrees with the deployment again, and it serves.
119
+ await restoreWith({});
120
+ await expect(add()).resolves.toBeDefined();
121
+ });
122
+ it("a dump whose journal carries a NULL digest is refused, and the scope is left as it was", async () => {
123
+ // A modern dump with an authored digest cleared — corrupted, or edited to hide a mismatch.
124
+ // A NULL cannot say where it came from, so the journal's fence refuses it on the way in.
125
+ const before = await journal();
126
+ await expect(restoreWith({ [AUTHORED]: null })).rejects.toThrow('a migration journal row must carry its sql_digest (#2066)');
127
+ expect(await journal()).toEqual(before);
128
+ await expect(add()).resolves.toBeDefined();
129
+ });
130
+ /** `clean` with the journal reshaped: its `sql_digest` cells dropped, and its DDL set to `ddl`. */
131
+ const withoutDigestColumn = (ddl) => ({
132
+ ...clean,
133
+ tables: clean.tables.map((tbl) => {
134
+ if (tbl.name !== '_substrat_migrations')
135
+ return tbl;
136
+ const at = tbl.columns.indexOf('sql_digest');
137
+ return {
138
+ ...tbl,
139
+ ddl: ddl ?? tbl.ddl,
140
+ columns: tbl.columns.filter((_, i) => i !== at),
141
+ rows: tbl.rows.map((r) => r.filter((_, i) => i !== at)),
142
+ };
143
+ }),
144
+ });
145
+ it('a dump taken before digests were recorded restores with every journal row marked legacy, and serves', async () => {
146
+ // The journal exactly as a pre-#2066 kernel exported it: the DDL `sqlite_master` held for it
147
+ // then, and the columns that DDL declares.
148
+ await host.restoreScope(staff, t, s, withoutDigestColumn(PRE_DIGEST_JOURNAL_DDL));
149
+ const rows = await journal();
150
+ expect([...rows.values()].map((r) => r.digest)).toEqual([...expected.keys()].map(() => 'legacy'));
151
+ await expect(add()).resolves.toBeDefined();
152
+ expect((await host.migrateScope(t, s)).status).not.toBe('failed');
153
+ await restoreWith({});
154
+ });
155
+ it('a current dump with the digest column stripped is not taken for a legacy one: refused, the scope as it was', async () => {
156
+ // Its journal DDL still declares sql_digest: neither a dump from before digests nor a whole
157
+ // one from after. Read as legacy, it would unprotect every row.
158
+ const before = await journal();
159
+ await expect(host.restoreScope(staff, t, s, withoutDigestColumn())).rejects.toThrow("the dump's _substrat_migrations declares sql_digest in its DDL but carries no such column");
160
+ expect(await journal()).toEqual(before);
161
+ await expect(add()).resolves.toBeDefined();
162
+ });
163
+ it('derived DDL is held to its declaration, not its digest', async () => {
164
+ const derived = [...expected.keys()].find((v) => v.startsWith('list/'));
165
+ const other = await sha256('-- the kernel spelled this index another way');
166
+ await restoreWith({ [derived]: other });
167
+ await expect(add()).resolves.toBeDefined();
168
+ expect((await host.migrateScope(t, s)).status).not.toBe('failed');
169
+ // Recorded as what ran, never rewritten.
170
+ expect((await journal()).get(derived)?.digest).toBe(other);
171
+ await restoreWith({});
172
+ });
173
+ });
174
+ }
175
+ //# sourceMappingURL=migration-digest-suite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-digest-suite.js","sourceRoot":"","sources":["../src/migration-digest-suite.ts"],"names":[],"mappings":"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"}