amalgm 0.1.245 → 0.1.246

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 (157) hide show
  1. package/README.md +12 -0
  2. package/lib/cli.js +146 -8
  3. package/lib/layout.js +89 -4
  4. package/lib/shared-realtime-tunnel.js +384 -43
  5. package/lib/supervisor.js +0 -3
  6. package/package.json +2 -2
  7. package/runtime/scripts/amalgm-mcp/adapters/contract.js +197 -0
  8. package/runtime/scripts/amalgm-mcp/adapters/filesystem.js +135 -0
  9. package/runtime/scripts/amalgm-mcp/adapters/git.js +84 -0
  10. package/runtime/scripts/amalgm-mcp/adapters/index.js +43 -0
  11. package/runtime/scripts/amalgm-mcp/adapters/reference.js +31 -0
  12. package/runtime/scripts/amalgm-mcp/adapters/truth.js +19 -0
  13. package/runtime/scripts/amalgm-mcp/browser/cookie-jar.js +20 -68
  14. package/runtime/scripts/amalgm-mcp/index.js +4 -0
  15. package/runtime/scripts/amalgm-mcp/lib/layout.js +89 -4
  16. package/runtime/scripts/amalgm-mcp/observer/README.md +259 -0
  17. package/runtime/scripts/amalgm-mcp/observer/apply.js +150 -0
  18. package/runtime/scripts/amalgm-mcp/observer/continuity.js +111 -0
  19. package/runtime/scripts/amalgm-mcp/observer/edges.js +111 -0
  20. package/runtime/scripts/amalgm-mcp/observer/index.js +1146 -0
  21. package/runtime/scripts/amalgm-mcp/observer/scan.js +387 -0
  22. package/runtime/scripts/amalgm-mcp/observer/store.js +262 -0
  23. package/runtime/scripts/amalgm-mcp/observer/verify.js +200 -0
  24. package/runtime/scripts/amalgm-mcp/observer/watch.js +62 -0
  25. package/runtime/scripts/amalgm-mcp/project-context/store.js +19 -87
  26. package/runtime/scripts/amalgm-mcp/registration/classify.js +33 -0
  27. package/runtime/scripts/amalgm-mcp/registration/entity-cloud.js +456 -0
  28. package/runtime/scripts/amalgm-mcp/registration/entity-content.js +345 -0
  29. package/runtime/scripts/amalgm-mcp/registration/index.js +752 -0
  30. package/runtime/scripts/amalgm-mcp/registration/refusal.js +42 -0
  31. package/runtime/scripts/amalgm-mcp/registration/repo-followers.js +127 -0
  32. package/runtime/scripts/amalgm-mcp/registration/repo-states.js +109 -0
  33. package/runtime/scripts/amalgm-mcp/registration/service.js +310 -0
  34. package/runtime/scripts/amalgm-mcp/registration/tree.js +178 -0
  35. package/runtime/scripts/amalgm-mcp/registry/evidence.js +826 -0
  36. package/runtime/scripts/amalgm-mcp/registry/index.js +666 -0
  37. package/runtime/scripts/amalgm-mcp/registry/store.js +290 -0
  38. package/runtime/scripts/amalgm-mcp/repocard/README.md +103 -0
  39. package/runtime/scripts/amalgm-mcp/repocard/apply.js +111 -0
  40. package/runtime/scripts/amalgm-mcp/repocard/capture-worker.js +94 -0
  41. package/runtime/scripts/amalgm-mcp/repocard/capture.js +149 -0
  42. package/runtime/scripts/amalgm-mcp/repocard/follow.js +310 -0
  43. package/runtime/scripts/amalgm-mcp/repocard/git.js +48 -0
  44. package/runtime/scripts/amalgm-mcp/repocard/index.js +48 -0
  45. package/runtime/scripts/amalgm-mcp/server/local-service-router.js +2 -0
  46. package/runtime/scripts/amalgm-mcp/server/routes/entities.js +287 -0
  47. package/runtime/scripts/amalgm-mcp/server/routes/state.js +0 -13
  48. package/runtime/scripts/amalgm-mcp/state/attachments.js +11 -45
  49. package/runtime/scripts/amalgm-mcp/state/db.js +46 -215
  50. package/runtime/scripts/amalgm-mcp/state/docs.js +301 -1101
  51. package/runtime/scripts/amalgm-mcp/state/mutation-contracts.js +0 -99
  52. package/runtime/scripts/amalgm-mcp/state/mutations.js +130 -507
  53. package/runtime/scripts/amalgm-mcp/state/promotions.js +1 -21
  54. package/runtime/scripts/amalgm-mcp/state/replicas.js +13 -134
  55. package/runtime/scripts/amalgm-mcp/state/shared-rest.js +3 -46
  56. package/runtime/scripts/amalgm-mcp/tests/adapters.test.js +379 -0
  57. package/runtime/scripts/amalgm-mcp/tests/browser-cookie-cloud.test.js +0 -193
  58. package/runtime/scripts/amalgm-mcp/tests/doorbell.matrix.life.test.js +449 -0
  59. package/runtime/scripts/amalgm-mcp/tests/doorbell.matrix.rig.js +107 -0
  60. package/runtime/scripts/amalgm-mcp/tests/doorbell.matrix.watch.test.js +213 -0
  61. package/runtime/scripts/amalgm-mcp/tests/entity-oracle/adapter.js +72 -0
  62. package/runtime/scripts/amalgm-mcp/tests/entity-oracle/assert.js +497 -0
  63. package/runtime/scripts/amalgm-mcp/tests/entity-oracle/bind.js +91 -0
  64. package/runtime/scripts/amalgm-mcp/tests/entity-oracle/graph.js +1031 -0
  65. package/runtime/scripts/amalgm-mcp/tests/entity-oracle/ledger.js +234 -0
  66. package/runtime/scripts/amalgm-mcp/tests/entity-oracle/referee.js +118 -0
  67. package/runtime/scripts/amalgm-mcp/tests/entity.oracle.test.js +1365 -0
  68. package/runtime/scripts/amalgm-mcp/tests/entity.registry.test.js +967 -0
  69. package/runtime/scripts/amalgm-mcp/tests/entity.rig.js +239 -0
  70. package/runtime/scripts/amalgm-mcp/tests/entity.storm.test.js +486 -0
  71. package/runtime/scripts/amalgm-mcp/tests/fake-watch.js +35 -0
  72. package/runtime/scripts/amalgm-mcp/tests/observer.links.test.js +289 -0
  73. package/runtime/scripts/amalgm-mcp/tests/observer.rig.js +103 -0
  74. package/runtime/scripts/amalgm-mcp/tests/observer.roots.test.js +505 -0
  75. package/runtime/scripts/amalgm-mcp/tests/observer.storm.test.js +389 -0
  76. package/runtime/scripts/amalgm-mcp/tests/observer.territory.test.js +845 -0
  77. package/runtime/scripts/amalgm-mcp/tests/observer.test.js +657 -0
  78. package/runtime/scripts/amalgm-mcp/tests/project-context.test.js +17 -32
  79. package/runtime/scripts/amalgm-mcp/tests/registration.service.test.js +256 -0
  80. package/runtime/scripts/amalgm-mcp/tests/registration.test.js +931 -0
  81. package/runtime/scripts/amalgm-mcp/tests/repocard.storm.test.js +284 -0
  82. package/runtime/scripts/amalgm-mcp/tests/repocard.test.js +371 -0
  83. package/runtime/scripts/amalgm-mcp/tests/repofollow.storm.test.js +435 -0
  84. package/runtime/scripts/amalgm-mcp/tests/repofollow.test.js +675 -0
  85. package/runtime/scripts/amalgm-mcp/tests/shared-tunnel-rehydration.test.js +0 -84
  86. package/runtime/scripts/amalgm-mcp/tests/state-docs.test.js +13 -376
  87. package/runtime/scripts/amalgm-mcp/tests/state-mutations.test.js +0 -309
  88. package/runtime/scripts/amalgm-mcp/tests/state-shared-replica.test.js +30 -758
  89. package/runtime/scripts/amalgm-mcp/tests/workspace-cards-store.test.js +3 -72
  90. package/runtime/scripts/amalgm-mcp/tests/workspace-cards.test.js +1 -89
  91. package/runtime/scripts/amalgm-mcp/tests/workspace-checkpoint-reducer.test.js +24 -55
  92. package/runtime/scripts/amalgm-mcp/tests/workspace-checkpoint.test.js +141 -424
  93. package/runtime/scripts/amalgm-mcp/tests/workspace-object-tunnel.test.js +3 -171
  94. package/runtime/scripts/amalgm-mcp/tests/workspace-objects.test.js +7 -220
  95. package/runtime/scripts/amalgm-mcp/tests/workspace-publication-invariants.test.js +236 -179
  96. package/runtime/scripts/amalgm-mcp/tests/workspace-reducer.test.js +326 -2228
  97. package/runtime/scripts/amalgm-mcp/tests/workspace-tree-cloud.test.js +3 -5319
  98. package/runtime/scripts/amalgm-mcp/tests/workspace-tree-core.test.js +1 -191
  99. package/runtime/scripts/amalgm-mcp/tests/workspace-tree-store.test.js +17 -3140
  100. package/runtime/scripts/amalgm-mcp/tests/workspace-wall.test.js +740 -137
  101. package/runtime/scripts/amalgm-mcp/workspace/access-store.js +1 -5
  102. package/runtime/scripts/amalgm-mcp/workspace/card.js +11 -35
  103. package/runtime/scripts/amalgm-mcp/workspace/cards.js +14 -39
  104. package/runtime/scripts/amalgm-mcp/workspace/checkpoint.js +147 -587
  105. package/runtime/scripts/amalgm-mcp/workspace/git.js +34 -406
  106. package/runtime/scripts/amalgm-mcp/workspace/merge.js +181 -102
  107. package/runtime/scripts/amalgm-mcp/workspace/objects.js +56 -221
  108. package/runtime/scripts/amalgm-mcp/workspace/reducer.js +538 -1964
  109. package/runtime/scripts/amalgm-mcp/workspace/rest.js +28 -49
  110. package/runtime/scripts/amalgm-mcp/workspace/store.js +4 -77
  111. package/runtime/scripts/amalgm-mcp/workspace/transition.js +192 -1734
  112. package/runtime/scripts/amalgm-mcp/workspace/tree/inclusion.js +1 -7
  113. package/runtime/scripts/amalgm-mcp/workspace/tree/local-state.js +61 -73
  114. package/runtime/scripts/amalgm-mcp/workspace/tree/reducer.js +6 -51
  115. package/runtime/scripts/amalgm-mcp/workspace/tree/snapshot.js +8 -79
  116. package/runtime/scripts/amalgm-mcp/workspace/tree-cloud.js +146 -3461
  117. package/runtime/scripts/amalgm-mcp/workspace/tree-store.js +71 -899
  118. package/runtime/scripts/amalgm-mcp/workspace/wall.js +538 -370
  119. package/runtime/scripts/local-gateway.js +1 -0
  120. package/runtime/scripts/amalgm-mcp/state/doc-disk.js +0 -550
  121. package/runtime/scripts/amalgm-mcp/tests/code-project-stream.test.js +0 -399
  122. package/runtime/scripts/amalgm-mcp/tests/fixtures/code-project-stream-v2.json +0 -1
  123. package/runtime/scripts/amalgm-mcp/tests/workspace-durable.test.js +0 -24
  124. package/runtime/scripts/amalgm-mcp/tests/workspace-local-intent.test.js +0 -1999
  125. package/runtime/scripts/amalgm-mcp/tests/workspace-native-file-transaction.test.js +0 -364
  126. package/runtime/scripts/amalgm-mcp/tests/workspace-provenance.test.js +0 -185
  127. package/runtime/scripts/amalgm-mcp/tests/workspace-reducer-liveness.test.js +0 -26
  128. package/runtime/scripts/amalgm-mcp/tests/workspace-sync-stats.test.js +0 -119
  129. package/runtime/scripts/amalgm-mcp/tests/workspace-transition.test.js +0 -1446
  130. package/runtime/scripts/amalgm-mcp/workspace/content.js +0 -32
  131. package/runtime/scripts/amalgm-mcp/workspace/durable.js +0 -45
  132. package/runtime/scripts/amalgm-mcp/workspace/intent.js +0 -535
  133. package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/BUILD.md +0 -31
  134. package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/bin/darwin-arm64/amalgm-file-transaction +0 -0
  135. package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/bin/linux-x64/amalgm-file-transaction +0 -0
  136. package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/build.mjs +0 -72
  137. package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/client.js +0 -165
  138. package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/go.mod +0 -5
  139. package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/go.sum +0 -2
  140. package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/main.go +0 -2201
  141. package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/manifest.json +0 -19
  142. package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/move_darwin.go +0 -18
  143. package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/move_linux.go +0 -18
  144. package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/process_darwin.go +0 -33
  145. package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/process_linux.go +0 -47
  146. package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/verify.mjs +0 -43
  147. package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/writers_darwin.go +0 -114
  148. package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/writers_linux.go +0 -84
  149. package/runtime/scripts/amalgm-mcp/workspace/project-stream.js +0 -771
  150. package/runtime/scripts/amalgm-mcp/workspace/provenance.js +0 -240
  151. package/runtime/scripts/amalgm-mcp/workspace/sync-stats.js +0 -240
  152. package/runtime/scripts/amalgm-mcp/workspace/tree/floor.js +0 -100
  153. package/runtime/scripts/amalgm-mcp/workspace/tree/observation-holds.js +0 -127
  154. package/runtime/scripts/amalgm-mcp/workspace/tree/path-state.js +0 -12
  155. package/runtime/scripts/amalgm-mcp/workspace/tree/root-binding.js +0 -125
  156. package/runtime/scripts/amalgm-mcp/workspace/tree/symlinks.js +0 -76
  157. package/runtime/scripts/amalgm-mcp/workspace/tree-materialization.js +0 -3766
@@ -8,36 +8,12 @@
8
8
  * is already backed by this WAL database.
9
9
  */
10
10
 
11
- const fs = require('fs');
12
11
  const path = require('path');
13
12
  const { ensureDir } = require('../lib/storage');
14
13
  const { LOCAL_DB_FILE, STORAGE_DIR } = require('../config');
15
14
 
16
15
  let db = null;
17
16
 
18
- const SHARED_RESOURCE_ATTACHMENTS_TABLE_SQL = `
19
- CREATE TABLE IF NOT EXISTS shared_resource_attachments (
20
- attachment_id TEXT PRIMARY KEY,
21
- resource_id TEXT NOT NULL UNIQUE,
22
- local_path TEXT NOT NULL UNIQUE,
23
- attachment_state TEXT NOT NULL DEFAULT 'pending'
24
- CHECK (attachment_state IN ('pending', 'syncing', 'attached', 'rejected')),
25
- attempt_count INTEGER NOT NULL DEFAULT 0 CHECK (attempt_count >= 0),
26
- next_attempt_at TEXT,
27
- last_error TEXT,
28
- -- First-attachment fence: local document mutations after this cursor
29
- -- are overlay work that the returned cloud snapshot cannot contain.
30
- journal_cursor INTEGER NOT NULL DEFAULT 0,
31
- created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
32
- updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
33
- );
34
- `;
35
-
36
- const SHARED_RESOURCE_ATTACHMENTS_INDEX_SQL = `
37
- CREATE INDEX IF NOT EXISTS shared_resource_attachments_outbox_idx
38
- ON shared_resource_attachments (attachment_state, next_attempt_at, created_at);
39
- `;
40
-
41
17
  // Prepared statements cached per database handle: preparing is a parse+plan
42
18
  // every time, and the realtime hot paths (event insert, replay reads, mirror
43
19
  // upserts, doc persistence) run the same fixed SQL for the process lifetime.
@@ -134,12 +110,10 @@ function migrate(database = openLocalDb()) {
134
110
  )),
135
111
  local_revision INTEGER,
136
112
  materialized_at TEXT,
137
- official_projected_at TEXT,
138
113
  event_seq INTEGER,
139
114
  attempt_count INTEGER NOT NULL DEFAULT 0 CHECK (attempt_count >= 0),
140
115
  next_attempt_at TEXT,
141
116
  last_error TEXT,
142
- failure_code TEXT,
143
117
  cloud_committed_at TEXT,
144
118
  created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
145
119
  updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
@@ -228,6 +202,22 @@ function migrate(database = openLocalDb()) {
228
202
  CREATE INDEX IF NOT EXISTS shared_resource_promotions_outbox_idx
229
203
  ON shared_resource_promotions (promotion_state, next_attempt_at, created_at);
230
204
 
205
+ CREATE TABLE IF NOT EXISTS shared_resource_attachments (
206
+ attachment_id TEXT PRIMARY KEY,
207
+ resource_id TEXT NOT NULL UNIQUE,
208
+ local_path TEXT NOT NULL UNIQUE,
209
+ attachment_state TEXT NOT NULL DEFAULT 'pending'
210
+ CHECK (attachment_state IN ('pending', 'syncing', 'attached', 'rejected')),
211
+ attempt_count INTEGER NOT NULL DEFAULT 0 CHECK (attempt_count >= 0),
212
+ next_attempt_at TEXT,
213
+ last_error TEXT,
214
+ created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
215
+ updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
216
+ );
217
+
218
+ CREATE INDEX IF NOT EXISTS shared_resource_attachments_outbox_idx
219
+ ON shared_resource_attachments (attachment_state, next_attempt_at, created_at);
220
+
231
221
  CREATE TABLE IF NOT EXISTS local_meta (
232
222
  key TEXT PRIMARY KEY,
233
223
  value TEXT,
@@ -365,6 +355,36 @@ function migrate(database = openLocalDb()) {
365
355
  CREATE INDEX IF NOT EXISTS workflow_cell_runs_run_idx
366
356
  ON workflow_cell_runs(run_id);
367
357
 
358
+ CREATE TABLE IF NOT EXISTS automation_deliveries (
359
+ id TEXT PRIMARY KEY,
360
+ kind TEXT NOT NULL CHECK (kind IN ('scheduled', 'event')),
361
+ trigger_id TEXT,
362
+ scheduled_for TEXT,
363
+ payload_json TEXT NOT NULL,
364
+ status TEXT NOT NULL DEFAULT 'pending'
365
+ CHECK (status IN ('pending', 'running', 'completed', 'rejected')),
366
+ attempt_count INTEGER NOT NULL DEFAULT 0 CHECK (attempt_count >= 0),
367
+ next_attempt_at TEXT,
368
+ lease_expires_at TEXT,
369
+ completed_trigger_ids_json TEXT NOT NULL DEFAULT '[]',
370
+ result_json TEXT,
371
+ last_error TEXT,
372
+ created_at TEXT NOT NULL,
373
+ updated_at TEXT NOT NULL,
374
+ completed_at TEXT,
375
+ FOREIGN KEY(trigger_id) REFERENCES automation_triggers(id) ON DELETE SET NULL
376
+ );
377
+
378
+ CREATE UNIQUE INDEX IF NOT EXISTS automation_deliveries_scheduled_slot_idx
379
+ ON automation_deliveries(trigger_id, scheduled_for)
380
+ WHERE kind = 'scheduled';
381
+
382
+ CREATE INDEX IF NOT EXISTS automation_deliveries_pending_idx
383
+ ON automation_deliveries(status, next_attempt_at, created_at);
384
+
385
+ CREATE INDEX IF NOT EXISTS automation_deliveries_trigger_idx
386
+ ON automation_deliveries(trigger_id, created_at DESC);
387
+
368
388
  CREATE TABLE IF NOT EXISTS scheduled_tasks (
369
389
  id TEXT PRIMARY KEY,
370
390
  name TEXT NOT NULL,
@@ -567,7 +587,6 @@ function migrate(database = openLocalDb()) {
567
587
  device_id TEXT,
568
588
  inode TEXT,
569
589
  trashed_at TEXT,
570
- trash_component_id TEXT,
571
590
  purged_at TEXT,
572
591
  missing_at TEXT,
573
592
  created_at TEXT NOT NULL,
@@ -588,23 +607,6 @@ function migrate(database = openLocalDb()) {
588
607
  ON workspace_nodes(workspace_id, device_id, inode)
589
608
  WHERE device_id IS NOT NULL AND inode IS NOT NULL AND purged_at IS NULL;
590
609
 
591
- -- A safe filesystem ambiguity is still a sync failure if it is visible
592
- -- only in one observer's return value. Keep every nonterminal tree wait
593
- -- durable and addressable so restart and Local Live diagnostics see the
594
- -- same held state until a later observation clears it.
595
- CREATE TABLE IF NOT EXISTS workspace_tree_observation_holds (
596
- workspace_id TEXT NOT NULL REFERENCES workspaces(id) ON UPDATE CASCADE ON DELETE CASCADE,
597
- hold_key TEXT NOT NULL,
598
- owner_kind TEXT NOT NULL DEFAULT 'observer',
599
- owner_id TEXT NOT NULL DEFAULT 'workspace-tree-observer',
600
- reason TEXT NOT NULL,
601
- node_id TEXT,
602
- operation_kind TEXT,
603
- paths_json TEXT NOT NULL,
604
- first_observed_at TEXT NOT NULL,
605
- PRIMARY KEY (workspace_id, hold_key)
606
- );
607
-
608
610
  CREATE TABLE IF NOT EXISTS workspace_access_state (
609
611
  workspace_id TEXT PRIMARY KEY REFERENCES workspaces(id) ON UPDATE CASCADE ON DELETE CASCADE,
610
612
  authority_epoch INTEGER NOT NULL DEFAULT 1 CHECK (authority_epoch > 0),
@@ -722,40 +724,15 @@ function migrate(database = openLocalDb()) {
722
724
  ON browser_login_sessions(expires_at);
723
725
 
724
726
  `);
725
- database.exec(SHARED_RESOURCE_ATTACHMENTS_TABLE_SQL);
726
- database.exec(SHARED_RESOURCE_ATTACHMENTS_INDEX_SQL);
727
727
 
728
728
  // event_log is already present on every installed machine. These nullable
729
729
  // projection fields are additive and leave every legacy row/wire shape
730
730
  // untouched while new SDK mutations carry their stable identity.
731
731
  ensureColumn(database, 'event_log', 'mutation_id', 'TEXT');
732
732
  ensureColumn(database, 'event_log', 'shared_resource_id', 'TEXT');
733
- ensureColumn(database, 'mutation_journal', 'failure_code', 'TEXT');
734
- ensureColumn(database, 'mutation_journal', 'official_projected_at', 'TEXT');
735
- ensureColumn(database, 'workspace_nodes', 'trash_component_id', 'TEXT');
736
- ensureColumn(
737
- database,
738
- 'workspace_tree_observation_holds',
739
- 'owner_kind',
740
- "TEXT NOT NULL DEFAULT 'observer'",
741
- );
742
- ensureColumn(
743
- database,
744
- 'workspace_tree_observation_holds',
745
- 'owner_id',
746
- "TEXT NOT NULL DEFAULT 'workspace-tree-observer'",
747
- );
748
- backfillWorkspaceTrashComponents(database);
749
733
  // Wave-3 canaries created shared_resource_promotions before the fence
750
734
  // cursor existed.
751
735
  ensureColumn(database, 'shared_resource_promotions', 'journal_cursor', 'INTEGER NOT NULL DEFAULT 0');
752
- ensureColumn(
753
- database,
754
- 'shared_resource_attachments',
755
- 'journal_cursor',
756
- 'INTEGER NOT NULL DEFAULT 0',
757
- );
758
- enforceAttachmentJournalFence(database);
759
736
  ensureColumn(
760
737
  database,
761
738
  'shared_resource_replicas',
@@ -772,108 +749,6 @@ function ensureColumn(database, tableName, columnName, declaration) {
772
749
  database.exec(`ALTER TABLE ${tableName} ADD COLUMN ${columnName} ${declaration}`);
773
750
  }
774
751
 
775
- function backfillWorkspaceTrashComponents(database) {
776
- database.prepare(`
777
- UPDATE workspace_nodes
778
- SET trash_component_id = NULL
779
- WHERE purged_at IS NOT NULL AND trash_component_id IS NOT NULL
780
- `).run();
781
- const workspaces = database.prepare(
782
- 'SELECT id, path FROM workspaces WHERE path IS NOT NULL',
783
- ).all();
784
- const update = database.prepare(`
785
- UPDATE workspace_nodes SET trash_component_id = ? WHERE id = ?
786
- `);
787
- database.transaction(() => {
788
- for (const workspace of workspaces) {
789
- const allRows = database.prepare(`
790
- SELECT id, parent_id, trashed_at
791
- FROM workspace_nodes
792
- WHERE workspace_id = ? AND trashed_at IS NOT NULL AND purged_at IS NULL
793
- `).all(workspace.id);
794
- const nodes = new Map(allRows.map((row) => [row.id, row]));
795
- const unstamped = database.prepare(`
796
- SELECT id FROM workspace_nodes
797
- WHERE workspace_id = ? AND trashed_at IS NOT NULL
798
- AND purged_at IS NULL AND trash_component_id IS NULL
799
- `).all(workspace.id);
800
- for (const { id } of unstamped) {
801
- const row = nodes.get(id);
802
- let current = row;
803
- let physicalRoot = null;
804
- while (current) {
805
- const candidate = path.join(
806
- path.dirname(path.resolve(workspace.path)),
807
- `.amalgm-tree-trash-${workspace.id}`,
808
- current.id,
809
- );
810
- if (fs.existsSync(candidate)) {
811
- physicalRoot = current.id;
812
- break;
813
- }
814
- current = nodes.get(current.parent_id) || null;
815
- }
816
- // Missing physical evidence is not permission to infer ownership
817
- // from a timestamp. Recovery may temporarily hold the carrier in
818
- // private staging; rerun this proof after recovery or remount.
819
- if (physicalRoot) update.run(physicalRoot, row.id);
820
- }
821
- }
822
- })();
823
- }
824
-
825
- function enforceAttachmentJournalFence(database) {
826
- const cursor = database.prepare('PRAGMA table_info(shared_resource_attachments)')
827
- .all()
828
- .find((column) => column.name === 'journal_cursor');
829
- if (!cursor) {
830
- throw new Error('shared attachment journal fence is missing');
831
- }
832
- database.prepare(`
833
- UPDATE shared_resource_attachments
834
- SET journal_cursor = 0
835
- WHERE journal_cursor IS NULL
836
- `).run();
837
- if (cursor.notnull === 1 && String(cursor.dflt_value) === '0') return;
838
-
839
- database.transaction(() => {
840
- database.exec('DROP INDEX IF EXISTS shared_resource_attachments_outbox_idx');
841
- database.exec(`
842
- ALTER TABLE shared_resource_attachments
843
- RENAME TO shared_resource_attachments_legacy_fence
844
- `);
845
- database.exec(SHARED_RESOURCE_ATTACHMENTS_TABLE_SQL);
846
- database.exec(`
847
- INSERT INTO shared_resource_attachments (
848
- attachment_id,
849
- resource_id,
850
- local_path,
851
- attachment_state,
852
- attempt_count,
853
- next_attempt_at,
854
- last_error,
855
- journal_cursor,
856
- created_at,
857
- updated_at
858
- )
859
- SELECT
860
- attachment_id,
861
- resource_id,
862
- local_path,
863
- attachment_state,
864
- attempt_count,
865
- next_attempt_at,
866
- last_error,
867
- COALESCE(journal_cursor, 0),
868
- created_at,
869
- updated_at
870
- FROM shared_resource_attachments_legacy_fence
871
- `);
872
- database.exec('DROP TABLE shared_resource_attachments_legacy_fence');
873
- database.exec(SHARED_RESOURCE_ATTACHMENTS_INDEX_SQL);
874
- })();
875
- }
876
-
877
752
  // repo-card identity moved from the path to minted replica ids
878
753
  // (repo-card@2). Cards are derived observations, so the v1 table is
879
754
  // dropped rather than migrated — the next refresh rebuilds every card
@@ -919,47 +794,7 @@ function ensureDocStatesSchema(database = openLocalDb()) {
919
794
  CREATE UNIQUE INDEX IF NOT EXISTS doc_states_node_id_idx
920
795
  ON doc_states(node_id)
921
796
  WHERE node_id IS NOT NULL;
922
-
923
- CREATE TABLE IF NOT EXISTS doc_disk_materializations (
924
- channel_id TEXT NOT NULL,
925
- mutation_id TEXT NOT NULL,
926
- local_resource TEXT NOT NULL,
927
- root TEXT NOT NULL,
928
- root_dev TEXT NOT NULL,
929
- root_ino TEXT NOT NULL,
930
- relative_path TEXT NOT NULL,
931
- transaction_id TEXT NOT NULL,
932
- operation_id TEXT NOT NULL,
933
- expected_json TEXT,
934
- observed_text TEXT,
935
- mutation_source TEXT,
936
- target_json TEXT,
937
- target_content BLOB,
938
- plan_kind TEXT NOT NULL DEFAULT 'mutation'
939
- CHECK (plan_kind IN ('mutation', 'snapshot')),
940
- snapshot_payload_json TEXT,
941
- snapshot_event_seq INTEGER,
942
- materialization_state TEXT NOT NULL DEFAULT 'based'
943
- CHECK (materialization_state IN ('based', 'prepared', 'crossed', 'superseded')),
944
- successor_channel_id TEXT,
945
- successor_mutation_id TEXT,
946
- created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
947
- updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
948
- PRIMARY KEY (channel_id, mutation_id)
949
- );
950
-
951
- CREATE INDEX IF NOT EXISTS doc_disk_materializations_resource_idx
952
- ON doc_disk_materializations(local_resource, created_at);
953
797
  `);
954
- ensureColumn(
955
- database,
956
- 'doc_disk_materializations',
957
- 'plan_kind',
958
- "TEXT NOT NULL DEFAULT 'mutation' CHECK (plan_kind IN ('mutation', 'snapshot'))",
959
- );
960
- ensureColumn(database, 'doc_disk_materializations', 'snapshot_payload_json', 'TEXT');
961
- ensureColumn(database, 'doc_disk_materializations', 'snapshot_event_seq', 'INTEGER');
962
- ensureColumn(database, 'doc_disk_materializations', 'mutation_source', 'TEXT');
963
798
  }
964
799
 
965
800
  // App-registered resources (state/app-resources.js): the engine-side mirror
@@ -990,13 +825,9 @@ function closeLocalDb() {
990
825
  }
991
826
 
992
827
  module.exports = {
993
- backfillWorkspaceTrashComponents,
994
828
  cachedStatement,
995
829
  closeLocalDb,
996
830
  ensureAppResourcesSchema,
997
831
  ensureDocStatesSchema,
998
832
  openLocalDb,
999
- _private: {
1000
- migrate,
1001
- },
1002
833
  };