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
@@ -52,11 +52,7 @@ function resolveAccess(nodeId, userIdInput, options = {}) {
52
52
  const database = options.database || openLocalDb();
53
53
  const userId = cleanUserId(userIdInput);
54
54
  const target = nodeRow(database, nodeId);
55
- // `missing_at` is a durable observation that the physical node disappeared;
56
- // it does not erase the UUID or its inherited authority. Reconciliation must
57
- // still be able to authorize and journal that offline deletion. Purge alone
58
- // retires the identity.
59
- if (!target || target.purged_at) return null;
55
+ if (!target || target.purged_at || target.missing_at) return null;
60
56
  const parents = new Map(
61
57
  database.prepare('SELECT id, parent_id FROM workspace_nodes WHERE workspace_id = ?')
62
58
  .all(target.workspace_id)
@@ -23,7 +23,7 @@ const {
23
23
  } = require('./git');
24
24
  const { cacheRootCommit, machineId, replicaForGitDir } = require('./identity');
25
25
 
26
- const CARD_CONTRACT = 'repo-card@3';
26
+ const CARD_CONTRACT = 'repo-card@2';
27
27
 
28
28
  // A transportable identity needs a dotted host: bare names resolve through
29
29
  // this machine's own config (ssh aliases, LAN names) and identify nothing
@@ -60,12 +60,7 @@ function cardKind(classified) {
60
60
  return classified.linked ? 'linked-worktree' : 'primary';
61
61
  }
62
62
 
63
- function reusableObjectSource(previousOid, currentOid, source, resourceId) {
64
- if (previousOid !== currentOid) return null;
65
- return source?.kind === 'bundle' && source.resourceId === resourceId ? source : null;
66
- }
67
-
68
- async function observeWorktree(classified, previousCard = null) {
63
+ async function observeWorktree(classified) {
69
64
  const worktreeRoot = classified.toplevel;
70
65
  const gitDir = await fs.promises.realpath(classified.gitDir);
71
66
  const replica = replicaForGitDir(gitDir);
@@ -82,32 +77,14 @@ async function observeWorktree(classified, previousCard = null) {
82
77
  }
83
78
 
84
79
  const repoIdentity = remote === null ? null : remoteIdentity(remote);
85
- const repoKey = repoIdentity || (anchor ? `root:${anchor}` : null);
86
- const resourceId = repoKey
87
- ? require('./wall').projectForPath(worktreeRoot)?.resourceId
80
+ const objects = head.oid && repoIdentity
81
+ ? await require('./objects').objectSourceFor(worktreeRoot, repoIdentity, head.oid)
88
82
  : null;
89
- const previous = previousCard?.replica === replica.replicaId
90
- && previousCard.repo?.remote === repoIdentity
91
- ? previousCard
92
- : null;
93
- const previousRefs = new Map((previous?.refs || []).map((ref) => [ref.name, ref]));
94
- const objectSources = new Map();
95
- const sourceFor = (oid, priorOid, priorSource) => {
96
- if (!oid || !repoKey) return null;
97
- if (objectSources.has(oid)) return objectSources.get(oid);
98
- const source = reusableObjectSource(priorOid, oid, priorSource, resourceId)
99
- || require('./objects').objectSourceFor(worktreeRoot, repoKey, oid);
100
- objectSources.set(oid, source);
101
- return source;
102
- };
103
- const objects = await sourceFor(head.oid, previous?.head?.oid, previous?.objects);
104
83
  const refs = await Promise.all(branches.map(async (branch) => ({
105
84
  ...branch,
106
- objects: await sourceFor(
107
- branch.oid,
108
- previousRefs.get(branch.name)?.oid,
109
- previousRefs.get(branch.name)?.objects,
110
- ),
85
+ objects: repoIdentity
86
+ ? await require('./objects').objectSourceFor(worktreeRoot, repoIdentity, branch.oid)
87
+ : null,
111
88
  })));
112
89
  return {
113
90
  card: CARD_CONTRACT,
@@ -131,7 +108,7 @@ async function observeWorktree(classified, previousCard = null) {
131
108
  }
132
109
 
133
110
  /**
134
- * Build the repo-card@3 for one worktree. `dirPath` may be any directory
111
+ * Build the repo-card@2 for one worktree. `dirPath` may be any directory
135
112
  * inside the worktree; the card is always for the worktree root. Throws
136
113
  * on anything that is not a worktree — discovery filters first.
137
114
  *
@@ -140,14 +117,14 @@ async function observeWorktree(classified, previousCard = null) {
140
117
  * moved. A repo still in motion after that simply cards again on the next
141
118
  * doorbell; every card is a true observation of some moment.
142
119
  */
143
- async function buildRepoCard(dirPath, previousCard = null) {
120
+ async function buildRepoCard(dirPath) {
144
121
  const classified = await classifyDirectory(dirPath);
145
122
  if (classified.kind !== 'worktree') {
146
123
  throw new Error(`cannot card ${classified.path}: ${classified.kind}`);
147
124
  }
148
- const observed = await observeWorktree(classified, previousCard);
125
+ const observed = await observeWorktree(classified);
149
126
  if (observed.head.oid === await headOid(classified.toplevel)) return observed;
150
- return observeWorktree(classified, observed);
127
+ return observeWorktree(classified);
151
128
  }
152
129
 
153
130
  /**
@@ -229,7 +206,6 @@ async function discoverWorktrees(rootPath) {
229
206
  }
230
207
 
231
208
  module.exports = {
232
- _test: { reusableObjectSource },
233
209
  CARD_CONTRACT,
234
210
  buildRepoCard,
235
211
  cardFingerprint,
@@ -37,7 +37,7 @@ const service = {
37
37
  reconcileTimer: null,
38
38
  workspaceTimer: null,
39
39
  unsubscribe: null,
40
- doorbells: new Map(), // replicaId → { watchSet, timer }
40
+ doorbells: new Map(), // replicaId → { watchers, timer }
41
41
  counters: { refreshes: 0, doorbellRings: 0 },
42
42
  lastRefresh: null,
43
43
  };
@@ -171,7 +171,6 @@ async function runRefresh() {
171
171
  service.counters.refreshes += 1;
172
172
 
173
173
  const roots = trackedRoots();
174
- const previousByPath = new Map(listRepoCards().map((card) => [card.path, card]));
175
174
  const targets = new Map(); // worktree root → registry root that reached it
176
175
  const skipped = [];
177
176
  const rootErrors = [];
@@ -190,7 +189,7 @@ async function runRefresh() {
190
189
  const built = [];
191
190
  for (const [target, root] of targets) {
192
191
  try {
193
- built.push({ card: await buildRepoCard(target, previousByPath.get(target)), root });
192
+ built.push({ card: await buildRepoCard(target), root });
194
193
  } catch (error) {
195
194
  skipped.push({ path: target, reason: 'observation-failed', error: error.message });
196
195
  }
@@ -322,7 +321,7 @@ async function refreshRepoCard(replicaId) {
322
321
  const row = db.prepare('SELECT * FROM repo_cards WHERE replica_id = ?').get(replicaId);
323
322
  if (!row) return null;
324
323
 
325
- const observedCard = await buildRepoCard(row.path, rowToCard(row));
324
+ const observedCard = await buildRepoCard(row.path);
326
325
  if (observedCard.replica !== replicaId) return refreshRepoCards();
327
326
  const card = observedCard;
328
327
  const fingerprint = cardFingerprint(card);
@@ -443,7 +442,7 @@ function nestedDirectories(root) {
443
442
  }
444
443
 
445
444
  function watchGitDir(card) {
446
- const watchSet = { handles: [], complete: true };
445
+ const watchers = [];
447
446
  const ring = () => ringDoorbell(card.replica);
448
447
  // The git dir itself carries HEAD, index, and operation markers; logs/
449
448
  // carries the reflog, which moves on every commit, checkout, and reset.
@@ -459,13 +458,9 @@ function watchGitDir(card) {
459
458
  for (const dir of new Set([...direct, ...refDirectories])) {
460
459
  try {
461
460
  const watcher = fs.watch(dir, ring);
462
- watcher.on('error', () => {
463
- watchSet.complete = false;
464
- watcher.close();
465
- });
466
- watchSet.handles.push(watcher);
461
+ watcher.on('error', () => watcher.close());
462
+ watchers.push(watcher);
467
463
  } catch {
468
- watchSet.complete = false;
469
464
  // The directory vanished between observation and watch; the next
470
465
  // reconcile pass re-syncs the bells.
471
466
  }
@@ -476,31 +471,27 @@ function watchGitDir(card) {
476
471
  if (relative === '.git' || relative.startsWith('.git/')) return;
477
472
  ring();
478
473
  });
479
- watcher.on('error', () => {
480
- watchSet.complete = false;
481
- watcher.close();
482
- });
483
- watchSet.handles.push(watcher);
474
+ watcher.on('error', () => watcher.close());
475
+ watchers.push(watcher);
484
476
  } catch {
485
- watchSet.complete = false;
486
477
  // The periodic card refresh remains the fallback on filesystems that
487
478
  // cannot watch a checkout recursively.
488
479
  }
489
- return watchSet;
480
+ return watchers;
490
481
  }
491
482
 
492
483
  function rebuildDoorbell(replicaId, card) {
493
484
  const bell = service.doorbells.get(replicaId);
494
485
  if (!bell) return;
495
- const previous = bell.watchSet;
496
- for (const watcher of previous.handles) watcher.close();
497
- bell.watchSet = watchGitDir(card);
486
+ const previous = bell.watchers;
487
+ bell.watchers = watchGitDir(card);
488
+ for (const watcher of previous) watcher.close();
498
489
  }
499
490
 
500
491
  function dropDoorbell(replicaId) {
501
492
  const bell = service.doorbells.get(replicaId);
502
493
  if (!bell) return;
503
- for (const watcher of bell.watchSet.handles) watcher.close();
494
+ for (const watcher of bell.watchers) watcher.close();
504
495
  if (bell.timer) clearTimeout(bell.timer);
505
496
  service.doorbells.delete(replicaId);
506
497
  }
@@ -515,9 +506,7 @@ function syncDoorbells(cards) {
515
506
  }
516
507
  for (const [replicaId, card] of healthy) {
517
508
  if (!service.doorbells.has(replicaId)) {
518
- service.doorbells.set(replicaId, { watchSet: watchGitDir(card), timer: null });
519
- } else if (!service.doorbells.get(replicaId).watchSet.complete) {
520
- rebuildDoorbell(replicaId, card);
509
+ service.doorbells.set(replicaId, { watchers: watchGitDir(card), timer: null });
521
510
  }
522
511
  }
523
512
  }
@@ -562,8 +551,6 @@ function repoCardServiceStats() {
562
551
  refreshes: service.counters.refreshes,
563
552
  doorbellRings: service.counters.doorbellRings,
564
553
  doorbells: service.doorbells.size,
565
- incompleteDoorbells: Array.from(service.doorbells.values())
566
- .filter((bell) => !bell.watchSet.complete).length,
567
554
  lastRefresh: service.lastRefresh,
568
555
  };
569
556
  }
@@ -575,16 +562,4 @@ module.exports = {
575
562
  repoCardServiceStats,
576
563
  startRepoCardService,
577
564
  stopRepoCardService,
578
- // Test hooks only. Filesystem delivery itself belongs to the host; these
579
- // expose the deterministic doorbell boundary behind that latency hint.
580
- _private: {
581
- rebuildDoorbell,
582
- ringDoorbell,
583
- watcherCount(replicaId) {
584
- return service.doorbells.get(replicaId)?.watchSet.handles.length || 0;
585
- },
586
- watcherComplete(replicaId) {
587
- return service.doorbells.get(replicaId)?.watchSet.complete === true;
588
- },
589
- },
590
565
  };