instar 1.3.698 → 1.3.699

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 (46) hide show
  1. package/dist/commands/server.d.ts.map +1 -1
  2. package/dist/commands/server.js +81 -7
  3. package/dist/commands/server.js.map +1 -1
  4. package/dist/core/CoherenceJournal.d.ts +10 -1
  5. package/dist/core/CoherenceJournal.d.ts.map +1 -1
  6. package/dist/core/CoherenceJournal.js +31 -3
  7. package/dist/core/CoherenceJournal.js.map +1 -1
  8. package/dist/core/MachinePoolRegistry.d.ts +13 -0
  9. package/dist/core/MachinePoolRegistry.d.ts.map +1 -1
  10. package/dist/core/MachinePoolRegistry.js +22 -3
  11. package/dist/core/MachinePoolRegistry.js.map +1 -1
  12. package/dist/core/OwnershipApplier.d.ts +21 -0
  13. package/dist/core/OwnershipApplier.d.ts.map +1 -1
  14. package/dist/core/OwnershipApplier.js +60 -5
  15. package/dist/core/OwnershipApplier.js.map +1 -1
  16. package/dist/core/OwnershipReconciler.d.ts +70 -1
  17. package/dist/core/OwnershipReconciler.d.ts.map +1 -1
  18. package/dist/core/OwnershipReconciler.js +177 -7
  19. package/dist/core/OwnershipReconciler.js.map +1 -1
  20. package/dist/core/TopicPinReplicatedStore.d.ts +68 -0
  21. package/dist/core/TopicPinReplicatedStore.d.ts.map +1 -0
  22. package/dist/core/TopicPinReplicatedStore.js +148 -0
  23. package/dist/core/TopicPinReplicatedStore.js.map +1 -0
  24. package/dist/core/TopicPlacementPinStore.d.ts +20 -2
  25. package/dist/core/TopicPlacementPinStore.d.ts.map +1 -1
  26. package/dist/core/TopicPlacementPinStore.js +5 -3
  27. package/dist/core/TopicPlacementPinStore.js.map +1 -1
  28. package/dist/core/devGatedFeatures.d.ts.map +1 -1
  29. package/dist/core/devGatedFeatures.js +6 -0
  30. package/dist/core/devGatedFeatures.js.map +1 -1
  31. package/dist/core/ownershipApplierWiring.d.ts +5 -0
  32. package/dist/core/ownershipApplierWiring.d.ts.map +1 -1
  33. package/dist/core/ownershipApplierWiring.js +3 -0
  34. package/dist/core/ownershipApplierWiring.js.map +1 -1
  35. package/dist/server/AgentServer.d.ts +2 -0
  36. package/dist/server/AgentServer.d.ts.map +1 -1
  37. package/dist/server/AgentServer.js +1 -0
  38. package/dist/server/AgentServer.js.map +1 -1
  39. package/dist/server/routes.d.ts +2 -0
  40. package/dist/server/routes.d.ts.map +1 -1
  41. package/dist/server/routes.js +33 -0
  42. package/dist/server/routes.js.map +1 -1
  43. package/package.json +1 -1
  44. package/src/data/builtin-manifest.json +47 -47
  45. package/upgrades/1.3.699.md +31 -0
  46. package/upgrades/side-effects/cross-machine-reconciler-convergence.md +56 -0
@@ -55,7 +55,6 @@ export class OwnershipApplier {
55
55
  let materialized = 0;
56
56
  try {
57
57
  const res = this.d.reader.query({ kind: 'topic-placement', limit: this.d.scanLimit ?? 1000 });
58
- // Collapse to the highest-epoch placement per topic across own + replica streams.
59
58
  const bestByTopic = new Map();
60
59
  for (const e of res.entries) {
61
60
  if (e.topic == null)
@@ -66,25 +65,81 @@ export class OwnershipApplier {
66
65
  continue;
67
66
  const key = String(e.topic);
68
67
  const cur = bestByTopic.get(key);
69
- if (!cur || epoch > cur.epoch)
70
- bestByTopic.set(key, { owner, epoch });
68
+ const cand = {
69
+ owner, epoch, streamOwner: e.machine,
70
+ status: e.data.status === 'transferring' ? 'transferring' : 'active',
71
+ transferTo: typeof e.data.transferTo === 'string' ? e.data.transferTo : undefined,
72
+ timestamp: typeof e.data.timestamp === 'number' && Number.isFinite(e.data.timestamp) ? e.data.timestamp : undefined,
73
+ drainInFlight: e.data.drainInFlight === true ? true : undefined,
74
+ };
75
+ if (!cur || epoch > cur.epoch) {
76
+ bestByTopic.set(key, cand);
77
+ }
78
+ else if (epoch === cur.epoch && cur.streamOwner !== cur.owner && cand.streamOwner === cand.owner) {
79
+ // Owner-anchored equal-epoch tie-break (Finding SE6): prefer the entry whose
80
+ // stream-owner == entry.owner (a `transferring` from the true owner is canonical),
81
+ // never iteration order.
82
+ bestByTopic.set(key, cand);
83
+ }
71
84
  }
72
85
  examined = bestByTopic.size;
86
+ const known = this.d.knownMachines?.();
87
+ const maxEpochJump = this.d.maxEpochJump ?? 1e9;
88
+ const skewTol = this.d.timestampSkewToleranceMs ?? 5 * 60 * 1000;
73
89
  for (const [sessionKey, best] of bestByTopic) {
74
90
  const local = this.d.store.read(sessionKey);
75
91
  const localEpoch = local?.ownershipEpoch ?? 0;
76
92
  if (best.epoch <= localEpoch)
77
93
  continue; // not newer → nothing to adopt (fast-forward only)
94
+ // Epoch fence (Finding SE2): a corrupt huge epoch jump can't wedge a topic forever.
95
+ if (best.epoch - localEpoch > maxEpochJump) {
96
+ this.log(`epoch-fence: refusing topic ${sessionKey} epoch ${best.epoch} (local ${localEpoch}, jump > ${maxEpochJump})`);
97
+ continue;
98
+ }
78
99
  const now = this.now();
100
+ // Resolve the materialized status. A `transferring` entry whose `transferTo` is
101
+ // target-less / unknown / == owner is DOWNGRADED to active(owner) — never materialized
102
+ // as an un-claimable permanently-stuck record (Findings AD3/SE1).
103
+ let status = 'active';
104
+ let transferTo;
105
+ let drainInFlight;
106
+ let timestamp = now;
107
+ if (best.status === 'transferring') {
108
+ const t = best.transferTo;
109
+ const validTarget = !!t && t !== best.owner && (!known || known.has(t));
110
+ if (validTarget) {
111
+ status = 'transferring';
112
+ transferTo = t;
113
+ drainInFlight = best.drainInFlight === true ? true : undefined;
114
+ // Carry the producer's `timestamp` (drain-grace + convergence deadline key on it),
115
+ // CLAMPED on receive (Finding SE8): future-beyond-skew → floor to now;
116
+ // implausibly-far-past → cap; in-bounds → preserve verbatim (AD2 drain timing).
117
+ const carried = best.timestamp;
118
+ if (typeof carried === 'number' && Number.isFinite(carried)) {
119
+ const maxPastMs = 24 * 60 * 60 * 1000;
120
+ if (carried > now + skewTol)
121
+ timestamp = now;
122
+ else if (carried < now - maxPastMs)
123
+ timestamp = now - maxPastMs;
124
+ else
125
+ timestamp = carried;
126
+ }
127
+ }
128
+ else {
129
+ this.log(`transferring→active downgrade for topic ${sessionKey}: invalid transferTo ${JSON.stringify(t)}`);
130
+ }
131
+ }
79
132
  const rec = {
80
133
  sessionKey,
81
134
  ownerMachineId: best.owner,
82
135
  ownershipEpoch: best.epoch,
83
- status: 'active',
136
+ status,
137
+ ...(transferTo ? { transferTo } : {}),
138
+ ...(drainInFlight ? { drainInFlight } : {}),
84
139
  // Adoption nonce keyed on (owner, epoch) — the same ordering identity the
85
140
  // journal uses; never a local action nonce.
86
141
  nonce: `applier:${best.owner}:${best.epoch}`,
87
- timestamp: now,
142
+ timestamp,
88
143
  updatedAt: new Date(now).toISOString(),
89
144
  };
90
145
  const r = this.d.store.casWrite(rec);
@@ -1 +1 @@
1
- {"version":3,"file":"OwnershipApplier.js","sourceRoot":"","sources":["../../src/core/OwnershipApplier.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"OwnershipApplier.js","sourceRoot":"","sources":["../../src/core/OwnershipApplier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AA4DH,MAAM,OAAO,gBAAgB;IACV,CAAC,CAAuB;IAEzC,YAAY,IAA0B;QACpC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC;IAChB,CAAC;IAEO,GAAG;QACT,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;IACpC,CAAC;IAEO,GAAG,CAAC,CAAS;QACnB,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,uBAAuB,CAAC,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED,8FAA8F;IACtF,WAAW;QACjB,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC;QAC/B,OAAO,OAAO,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3C,CAAC;IAED;;;;OAIG;IACH,IAAI;QACF,IAAI,QAAQ,GAAG,CAAC,CAAC;QACjB,IAAI,YAAY,GAAG,CAAC,CAAC;QACrB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,SAAS,IAAI,IAAI,EAAE,CAAC,CAAC;YAS9F,MAAM,WAAW,GAAG,IAAI,GAAG,EAAgB,CAAC;YAC5C,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;gBAC5B,IAAI,CAAC,CAAC,KAAK,IAAI,IAAI;oBAAE,SAAS;gBAC9B,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;gBACnE,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACrF,IAAI,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC;oBAAE,SAAS;gBAC9D,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;gBAC5B,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBACjC,MAAM,IAAI,GAAS;oBACjB,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC,OAAO;oBACpC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,KAAK,cAAc,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ;oBACpE,UAAU,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS;oBACjF,SAAS,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,SAAS,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;oBACnH,aAAa,EAAE,CAAC,CAAC,IAAI,CAAC,aAAa,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;iBAChE,CAAC;gBACF,IAAI,CAAC,GAAG,IAAI,KAAK,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC;oBAC9B,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;gBAC7B,CAAC;qBAAM,IAAI,KAAK,KAAK,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,WAAW,KAAK,GAAG,CAAC,KAAK,IAAI,IAAI,CAAC,WAAW,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC;oBACnG,6EAA6E;oBAC7E,mFAAmF;oBACnF,yBAAyB;oBACzB,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;gBAC7B,CAAC;YACH,CAAC;YACD,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC;YAE5B,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,aAAa,EAAE,EAAE,CAAC;YACvC,MAAM,YAAY,GAAG,IAAI,CAAC,CAAC,CAAC,YAAY,IAAI,GAAG,CAAC;YAChD,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,wBAAwB,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;YAEjE,KAAK,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,IAAI,WAAW,EAAE,CAAC;gBAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;gBAC5C,MAAM,UAAU,GAAG,KAAK,EAAE,cAAc,IAAI,CAAC,CAAC;gBAC9C,IAAI,IAAI,CAAC,KAAK,IAAI,UAAU;oBAAE,SAAS,CAAC,mDAAmD;gBAC3F,oFAAoF;gBACpF,IAAI,IAAI,CAAC,KAAK,GAAG,UAAU,GAAG,YAAY,EAAE,CAAC;oBAC3C,IAAI,CAAC,GAAG,CAAC,+BAA+B,UAAU,UAAU,IAAI,CAAC,KAAK,WAAW,UAAU,YAAY,YAAY,GAAG,CAAC,CAAC;oBACxH,SAAS;gBACX,CAAC;gBACD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBACvB,gFAAgF;gBAChF,uFAAuF;gBACvF,kEAAkE;gBAClE,IAAI,MAAM,GAA8B,QAAQ,CAAC;gBACjD,IAAI,UAA8B,CAAC;gBACnC,IAAI,aAAkC,CAAC;gBACvC,IAAI,SAAS,GAAG,GAAG,CAAC;gBACpB,IAAI,IAAI,CAAC,MAAM,KAAK,cAAc,EAAE,CAAC;oBACnC,MAAM,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC;oBAC1B,MAAM,WAAW,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;oBACxE,IAAI,WAAW,EAAE,CAAC;wBAChB,MAAM,GAAG,cAAc,CAAC;wBACxB,UAAU,GAAG,CAAC,CAAC;wBACf,aAAa,GAAG,IAAI,CAAC,aAAa,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;wBAC/D,mFAAmF;wBACnF,uEAAuE;wBACvE,gFAAgF;wBAChF,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC;wBAC/B,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;4BAC5D,MAAM,SAAS,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;4BACtC,IAAI,OAAO,GAAG,GAAG,GAAG,OAAO;gCAAE,SAAS,GAAG,GAAG,CAAC;iCACxC,IAAI,OAAO,GAAG,GAAG,GAAG,SAAS;gCAAE,SAAS,GAAG,GAAG,GAAG,SAAS,CAAC;;gCAC3D,SAAS,GAAG,OAAO,CAAC;wBAC3B,CAAC;oBACH,CAAC;yBAAM,CAAC;wBACN,IAAI,CAAC,GAAG,CAAC,2CAA2C,UAAU,wBAAwB,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;oBAC7G,CAAC;gBACH,CAAC;gBACD,MAAM,GAAG,GAA2B;oBAClC,UAAU;oBACV,cAAc,EAAE,IAAI,CAAC,KAAK;oBAC1B,cAAc,EAAE,IAAI,CAAC,KAAK;oBAC1B,MAAM;oBACN,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBACrC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBAC3C,0EAA0E;oBAC1E,4CAA4C;oBAC5C,KAAK,EAAE,WAAW,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,EAAE;oBAC5C,SAAS;oBACT,SAAS,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE;iBACvC,CAAC;gBACF,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;gBACrC,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC;oBACT,YAAY,EAAE,CAAC;oBACf,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;oBAChC,IAAI,CAAC,GAAG,CACN,sBAAsB,UAAU,YAAY,IAAI,CAAC,KAAK,WAAW,IAAI,CAAC,KAAK,EAAE;wBAC3E,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI;4BAC1B,CAAC,CAAC,sCAAsC;4BACxC,CAAC,CAAC,IAAI;gCACJ,CAAC,CAAC,gCAAgC;gCAClC,CAAC,CAAC,EAAE,CAAC,CACZ,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,8EAA8E;YAC9E,iFAAiF;YACjF,IAAI,CAAC,GAAG,CAAC,gBAAgB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC/E,CAAC;QACD,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;IACpC,CAAC;CACF"}
@@ -37,6 +37,7 @@
37
37
  */
38
38
  import type { SessionOwnershipRegistry, CasResult } from './SessionOwnershipRegistry.js';
39
39
  import type { TopicPlacementPinStore } from './TopicPlacementPinStore.js';
40
+ import type { HlcTimestamp } from './HybridLogicalClock.js';
40
41
  export interface ReconcilerMachineView {
41
42
  machineId: string;
42
43
  online: boolean;
@@ -50,6 +51,18 @@ export interface OwnershipReconcilerDeps {
50
51
  dryRun: () => boolean;
51
52
  selfMachineId: string;
52
53
  pinStore: TopicPlacementPinStore;
54
+ /**
55
+ * Cross-machine convergence (Fix #2): the merged ADVISORY replicated pins (move-intent
56
+ * from peers, HLC-ordered). The OWNING machine has no LOCAL pin for a stuck move (the pin
57
+ * was set on the lease-holder) — this is how it sees "you are pinned away" and starts the
58
+ * cooperative transfer. ADVISORY only: validated (known+online target) and able to trigger
59
+ * the owner's OWN transfer, never a force-claim. Absent ⇒ local-pin-only (single-machine
60
+ * / un-wired), today's behavior. Each entry is `{preferredMachine, hlc}` for a pinned topic.
61
+ */
62
+ advisoryPins?: () => Map<number, {
63
+ preferredMachine: string;
64
+ hlc: HlcTimestamp;
65
+ }>;
53
66
  ownership: SessionOwnershipRegistry;
54
67
  /** All REGISTERED machines (online and not). [] or [self] → strict no-op. */
55
68
  machines: () => ReconcilerMachineView[];
@@ -63,7 +76,10 @@ export interface OwnershipReconcilerDeps {
63
76
  /** Journal pairing (§3.3): every landed CAS emits a placement entry. */
64
77
  emitPlacement: (sessionKey: string, r: CasResult & {
65
78
  ok: true;
66
- }, reason: 'reconcile-transfer' | 'reconcile-claim' | 'reconcile-force-claim' | 'reconcile-adopt') => void;
79
+ }, reason: 'reconcile-transfer' | 'reconcile-claim' | 'reconcile-force-claim' | 'reconcile-adopt' | 'reconcile-abort-transfer') => void;
80
+ /** Fix #3 / Finding N4: how long a `transferring` may sit (from its `timestamp`) before
81
+ * the owner aborts a transfer toward an unreachable target. Default 120s. */
82
+ transferDeadlineMs?: number;
67
83
  /** Pin must be stable this long before the owner acts (flap debounce). */
68
84
  debounceMs?: number;
69
85
  /** Bounded safe-point wait: after this, transfer even if the session is busy. */
@@ -79,24 +95,77 @@ export interface ReconcileTickReport {
79
95
  claims: number;
80
96
  forceClaims: number;
81
97
  adoptions: number;
98
+ /** Fix #3 / Finding N4: a stuck `transferring(self→T)` whose target T went unreachable
99
+ * past the deadline was aborted back to active(self) — recovery, not a new stall. */
100
+ aborts: number;
82
101
  deferredBusy: number;
83
102
  deferredDebounce: number;
84
103
  deferredNoEvidence: number;
85
104
  dryRun: boolean;
86
105
  skipped?: 'disabled' | 'single-machine';
87
106
  }
107
+ /** Read-only per-topic decision explanation (Observable Intelligence): what the
108
+ * reconciler WOULD do for one topic right now, and why — for live debugging a
109
+ * stuck convergence without acting. Produced by OwnershipReconciler.explainTopic. */
110
+ export type ReconcileDecision = 'no-pin' | 'converged' | 'claim' | 'await-other-claim' | 'adopt' | 'transfer' | 'deferred-debounce' | 'deferred-busy' | 'force-claim' | 'deferred-no-evidence' | 'abort-transfer' | 'not-my-move' | 'skipped';
111
+ export interface TopicReconcileExplanation {
112
+ sessionKey: string;
113
+ self: string;
114
+ machinesCount: number;
115
+ pinned?: boolean;
116
+ preferredMachine?: string;
117
+ owner?: string | null;
118
+ status?: string | null;
119
+ decision: ReconcileDecision;
120
+ reason: string;
121
+ }
88
122
  export declare class OwnershipReconciler {
89
123
  private readonly d;
90
124
  /** First time we observed each topic's CURRENT conflict (cleared on convergence). */
91
125
  private readonly conflictSince;
126
+ /** Observability (Observable Intelligence): the most recent tick's report + when. */
127
+ private lastReport;
128
+ private lastTickAtMs;
92
129
  constructor(deps: OwnershipReconcilerDeps);
130
+ /** Stamp the last-tick observability state and return the report (single funnel
131
+ * for every tick() exit so the status readout is never stale on an early return). */
132
+ private finish;
93
133
  private now;
94
134
  private log;
135
+ /** The local pin's skew-proof HLC: its stored `hlc` (Fix #2), else a fallback derived
136
+ * from `updatedAt` (the migration for pre-Fix-#2 pins). */
137
+ private deriveLocalPinHlc;
138
+ /**
139
+ * The EFFECTIVE pin per topic = the union of LOCAL pins (authoritative on the machine
140
+ * that set them) and ADVISORY replicated pins (the move-intent the OWNER receives),
141
+ * resolved by HLC precedence (Finding N3): a stale LOCAL self-pin must never mask a
142
+ * FRESHER replicated move-intent. With no advisory dep this is exactly the local pins
143
+ * (today's behavior). A replicated pin is ADVISORY — it only ever yields a `preferredMachine`
144
+ * the owner cooperatively transfers toward; the force-claim path never reads it.
145
+ */
146
+ private effectivePins;
95
147
  /**
96
148
  * One reconcile pass. Deterministic over local state; bounded by the number
97
149
  * of pinned topics. Safe to call on any cadence.
98
150
  */
99
151
  tick(): ReconcileTickReport;
100
152
  private act;
153
+ /**
154
+ * Read-only diagnostic: what the reconciler decides for ONE topic right now, and
155
+ * WHY — without acting. A documented mirror of tick()'s decision tree (kept in
156
+ * lock-step by parity unit tests). Answers "why is topic N not converging?" live —
157
+ * the exact gap that left the cross-machine stuck-move bug a black box (2026-06-30).
158
+ */
159
+ explainTopic(sessionKey: string): TopicReconcileExplanation;
160
+ /** Reconciler status (Observable Intelligence): last tick report + when, plus the
161
+ * live enabled/dryRun gate and machine-count the reconciler actually sees. */
162
+ status(): {
163
+ enabled: boolean;
164
+ dryRun: boolean;
165
+ lastTickAt: string | null;
166
+ lastReport: ReconcileTickReport | null;
167
+ machinesCount: number;
168
+ selfMachineId: string;
169
+ };
101
170
  }
102
171
  //# sourceMappingURL=OwnershipReconciler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"OwnershipReconciler.d.ts","sourceRoot":"","sources":["../../src/core/OwnershipReconciler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAO,KAAK,EAAE,wBAAwB,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAEzF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAE1E,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,gFAAgF;IAChF,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,uBAAuB;IACtC,uCAAuC;IACvC,OAAO,EAAE,MAAM,OAAO,CAAC;IACvB,4DAA4D;IAC5D,MAAM,EAAE,MAAM,OAAO,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,sBAAsB,CAAC;IACjC,SAAS,EAAE,wBAAwB,CAAC;IACpC,6EAA6E;IAC7E,QAAQ,EAAE,MAAM,qBAAqB,EAAE,CAAC;IACxC;;;;;OAKG;IACH,WAAW,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC;IAC7C,wEAAwE;IACxE,aAAa,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,GAAG;QAAE,EAAE,EAAE,IAAI,CAAA;KAAE,EAAE,MAAM,EAAE,oBAAoB,GAAG,iBAAiB,GAAG,uBAAuB,GAAG,iBAAiB,KAAK,IAAI,CAAC;IACzK,0EAA0E;IAC1E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iFAAiF;IACjF,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,kEAAkE;IAClE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAChC;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,UAAU,GAAG,gBAAgB,CAAC;CACzC;AAaD,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAC,CAAC,CAA0B;IAC5C,qFAAqF;IACrF,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA6B;gBAE/C,IAAI,EAAE,uBAAuB;IAIzC,OAAO,CAAC,GAAG;IAGX,OAAO,CAAC,GAAG;IAIX;;;OAGG;IACH,IAAI,IAAI,mBAAmB;IA2G3B,OAAO,CAAC,GAAG;CA4BZ"}
1
+ {"version":3,"file":"OwnershipReconciler.d.ts","sourceRoot":"","sources":["../../src/core/OwnershipReconciler.ts"],"names":[],"mappings":"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"}
@@ -35,6 +35,7 @@
35
35
  * the tick returns before touching any machinery when fewer than 2 machines
36
36
  * are registered.
37
37
  */
38
+ import { compareHlc } from './TopicPinReplicatedStore.js';
38
39
  const DEFAULT_DEBOUNCE_MS = 30_000;
39
40
  /** WS1.2 drain-grace: hold the transferring-to-me claim back long enough for a
40
41
  * LIVE owner's bounded drain (SessionDrainRunner) to finish and land the claim
@@ -45,13 +46,26 @@ const DEFAULT_DEBOUNCE_MS = 30_000;
45
46
  const DEFAULT_DRAIN_CLAIM_GRACE_MS = 45_000;
46
47
  const DEFAULT_SAFE_POINT_DEADLINE_MS = 120_000;
47
48
  const DEFAULT_DEATH_EVIDENCE_MS = 180_000;
49
+ /** Fix #3 / Finding N4: how long a `transferring` may sit before the owner aborts a
50
+ * transfer toward an unreachable target (the convergence deadline). */
51
+ const DEFAULT_TRANSFER_DEADLINE_MS = 120_000;
48
52
  export class OwnershipReconciler {
49
53
  d;
50
54
  /** First time we observed each topic's CURRENT conflict (cleared on convergence). */
51
55
  conflictSince = new Map();
56
+ /** Observability (Observable Intelligence): the most recent tick's report + when. */
57
+ lastReport = null;
58
+ lastTickAtMs = 0;
52
59
  constructor(deps) {
53
60
  this.d = deps;
54
61
  }
62
+ /** Stamp the last-tick observability state and return the report (single funnel
63
+ * for every tick() exit so the status readout is never stale on an early return). */
64
+ finish(report) {
65
+ this.lastReport = report;
66
+ this.lastTickAtMs = this.now();
67
+ return report;
68
+ }
55
69
  now() {
56
70
  return (this.d.now ?? Date.now)();
57
71
  }
@@ -61,30 +75,70 @@ export class OwnershipReconciler {
61
75
  }
62
76
  catch { /* observability never gates */ }
63
77
  }
78
+ /** The local pin's skew-proof HLC: its stored `hlc` (Fix #2), else a fallback derived
79
+ * from `updatedAt` (the migration for pre-Fix-#2 pins). */
80
+ deriveLocalPinHlc(pin) {
81
+ if (pin.hlc)
82
+ return pin.hlc;
83
+ return { physical: Date.parse(pin.updatedAt) || 0, logical: 0, node: this.d.selfMachineId };
84
+ }
85
+ /**
86
+ * The EFFECTIVE pin per topic = the union of LOCAL pins (authoritative on the machine
87
+ * that set them) and ADVISORY replicated pins (the move-intent the OWNER receives),
88
+ * resolved by HLC precedence (Finding N3): a stale LOCAL self-pin must never mask a
89
+ * FRESHER replicated move-intent. With no advisory dep this is exactly the local pins
90
+ * (today's behavior). A replicated pin is ADVISORY — it only ever yields a `preferredMachine`
91
+ * the owner cooperatively transfers toward; the force-claim path never reads it.
92
+ */
93
+ effectivePins() {
94
+ const local = this.d.pinStore.all();
95
+ const advisory = this.d.advisoryPins?.();
96
+ if (!advisory || advisory.size === 0)
97
+ return local;
98
+ // Validate PRIMARY = membership/liveness (skew-proof): only act on a replicated pin
99
+ // whose target is a KNOWN and currently-ONLINE machine (Findings N2/SE4/AD5). A stale
100
+ // advisory pointing at a departed/offline machine must NOT trigger a transfer.
101
+ const online = new Set(this.d.machines().filter((m) => m.online).map((m) => m.machineId));
102
+ const out = { ...local };
103
+ for (const [topic, adv] of advisory) {
104
+ if (!online.has(adv.preferredMachine))
105
+ continue; // unknown/offline target → ignore advisory
106
+ const key = String(topic);
107
+ const localPin = local[key];
108
+ const advPin = { preferredMachine: adv.preferredMachine, pinned: true, updatedAt: new Date(adv.hlc.physical).toISOString(), hlc: adv.hlc };
109
+ if (!localPin || !localPin.pinned) {
110
+ out[key] = advPin; // no authoritative local pin → advisory move-intent IS the effective pin
111
+ }
112
+ else if (compareHlc(adv.hlc, this.deriveLocalPinHlc(localPin)) > 0) {
113
+ out[key] = advPin; // replicated intent is newer (HLC) → it wins (N3)
114
+ }
115
+ }
116
+ return out;
117
+ }
64
118
  /**
65
119
  * One reconcile pass. Deterministic over local state; bounded by the number
66
120
  * of pinned topics. Safe to call on any cadence.
67
121
  */
68
122
  tick() {
69
123
  const report = {
70
- examined: 0, transfers: 0, claims: 0, forceClaims: 0, adoptions: 0,
124
+ examined: 0, transfers: 0, claims: 0, forceClaims: 0, adoptions: 0, aborts: 0,
71
125
  deferredBusy: 0, deferredDebounce: 0, deferredNoEvidence: 0,
72
126
  dryRun: this.d.dryRun(),
73
127
  };
74
128
  if (!this.d.enabled()) {
75
129
  report.skipped = 'disabled';
76
- return report;
130
+ return this.finish(report);
77
131
  }
78
132
  const machines = this.d.machines();
79
133
  if (machines.length < 2) {
80
134
  // Spec invariant 6: single-machine strict no-op — no machinery entered.
81
135
  report.skipped = 'single-machine';
82
- return report;
136
+ return this.finish(report);
83
137
  }
84
138
  const now = this.now();
85
139
  const self = this.d.selfMachineId;
86
140
  const byId = new Map(machines.map((m) => [m.machineId, m]));
87
- for (const [sessionKey, pin] of Object.entries(this.d.pinStore.all())) {
141
+ for (const [sessionKey, pin] of Object.entries(this.effectivePins())) {
88
142
  if (!pin.pinned || !pin.preferredMachine)
89
143
  continue;
90
144
  const rec = this.d.ownership.read(sessionKey);
@@ -112,8 +166,22 @@ export class OwnershipReconciler {
112
166
  this.act(report, 'claims', sessionKey, { type: 'claim', machineId: self }, 'reconcile-claim');
113
167
  continue;
114
168
  }
115
- if (rec?.status === 'transferring')
116
- continue; // someone else's claim to make
169
+ if (rec?.status === 'transferring') {
170
+ // ── N4 recovery: I am the draining SOURCE and my transfer TARGET went
171
+ // unreachable past the deadline → abort-transfer back to active(self), so a
172
+ // dead-target handoff self-heals instead of freezing the topic (the "don't
173
+ // trade one stuck-state for another" finding). Owner-only by FSM construction.
174
+ if (owner === self && rec.transferTo && rec.transferTo !== self) {
175
+ const targetView = byId.get(rec.transferTo);
176
+ const targetUnreachable = !targetView || !targetView.online;
177
+ const pastDeadline = now - (rec.timestamp ?? now) >= (this.d.transferDeadlineMs ?? DEFAULT_TRANSFER_DEADLINE_MS);
178
+ if (targetUnreachable && pastDeadline) {
179
+ this.act(report, 'aborts', sessionKey, { type: 'abort-transfer', machineId: self }, 'reconcile-abort-transfer');
180
+ continue;
181
+ }
182
+ }
183
+ continue; // still in flight / someone else's claim to make
184
+ }
117
185
  // ── Case D: no live record and the pin names ME → adopt (place→claim).
118
186
  if ((!rec || rec.status === 'released') && pin.preferredMachine === self) {
119
187
  const placed = this.act(report, 'adoptions', sessionKey, { type: 'place', machineId: self }, 'reconcile-adopt');
@@ -170,7 +238,7 @@ export class OwnershipReconciler {
170
238
  }
171
239
  // Neither owner nor pin target: not my move this tick.
172
240
  }
173
- return report;
241
+ return this.finish(report);
174
242
  }
175
243
  act(report, counter, sessionKey, action, reason, countOnce = false) {
176
244
  if (this.d.dryRun()) {
@@ -198,5 +266,107 @@ export class OwnershipReconciler {
198
266
  this.log(`${action.type} rejected for ${sessionKey} (${'reason' in r ? r.reason : 'unknown'}) — will re-evaluate next tick`);
199
267
  return false;
200
268
  }
269
+ /**
270
+ * Read-only diagnostic: what the reconciler decides for ONE topic right now, and
271
+ * WHY — without acting. A documented mirror of tick()'s decision tree (kept in
272
+ * lock-step by parity unit tests). Answers "why is topic N not converging?" live —
273
+ * the exact gap that left the cross-machine stuck-move bug a black box (2026-06-30).
274
+ */
275
+ explainTopic(sessionKey) {
276
+ const self = this.d.selfMachineId;
277
+ const machines = this.d.machines();
278
+ const base = { sessionKey, self, machinesCount: machines.length };
279
+ if (!this.d.enabled())
280
+ return { ...base, decision: 'skipped', reason: 'reconciler disabled' };
281
+ if (machines.length < 2)
282
+ return { ...base, decision: 'skipped', reason: 'single-machine (machines() < 2)' };
283
+ const pin = this.effectivePins()[sessionKey];
284
+ if (!pin || !pin.pinned || !pin.preferredMachine) {
285
+ return { ...base, decision: 'no-pin', reason: "no pinned preferredMachine (local or advisory replicated) for this topic" };
286
+ }
287
+ const rec = this.d.ownership.read(sessionKey);
288
+ const owner = rec && rec.status !== 'released' ? rec.ownerMachineId : null;
289
+ const ctx = { ...base, pinned: true, preferredMachine: pin.preferredMachine, owner, status: rec?.status ?? null };
290
+ if (owner === pin.preferredMachine && rec?.status === 'active') {
291
+ return { ...ctx, decision: 'converged', reason: 'owner == pin target and active' };
292
+ }
293
+ if (rec?.status === 'transferring' && rec.transferTo === self) {
294
+ return { ...ctx, decision: 'claim', reason: 'transferring to me → would claim (completes handoff)' };
295
+ }
296
+ if (rec?.status === 'transferring') {
297
+ const now0 = this.now();
298
+ if (owner === self && rec.transferTo && rec.transferTo !== self) {
299
+ const tv = machines.find((m) => m.machineId === rec.transferTo);
300
+ const unreachable = !tv || !tv.online;
301
+ const past = now0 - (rec.timestamp ?? now0) >= (this.d.transferDeadlineMs ?? DEFAULT_TRANSFER_DEADLINE_MS);
302
+ if (unreachable && past) {
303
+ return { ...ctx, decision: 'abort-transfer', reason: `transfer target ${rec.transferTo} unreachable past deadline → would abort back to active(self)` };
304
+ }
305
+ }
306
+ return { ...ctx, decision: 'await-other-claim', reason: `transferring to ${rec.transferTo ?? '?'} — that machine claims` };
307
+ }
308
+ if ((!rec || rec.status === 'released') && pin.preferredMachine === self) {
309
+ return { ...ctx, decision: 'adopt', reason: 'no live record + pin names me → would place→claim' };
310
+ }
311
+ if (!rec || rec.status === 'released') {
312
+ return { ...ctx, decision: 'not-my-move', reason: 'no live record + pin names another machine' };
313
+ }
314
+ const now = this.now();
315
+ if (owner === self) {
316
+ const pinAgeMs = now - Date.parse(pin.updatedAt);
317
+ const debounceMs = this.d.debounceMs ?? DEFAULT_DEBOUNCE_MS;
318
+ if (Number.isFinite(pinAgeMs) && pinAgeMs < debounceMs) {
319
+ return { ...ctx, decision: 'deferred-debounce', reason: `pin age ${Math.round(pinAgeMs)}ms < debounce ${debounceMs}ms` };
320
+ }
321
+ const since = this.conflictSince.get(sessionKey) ?? now;
322
+ const busy = this.d.isTopicBusy(sessionKey);
323
+ const pastDeadline = now - since >= (this.d.safePointDeadlineMs ?? DEFAULT_SAFE_POINT_DEADLINE_MS);
324
+ if (busy && !pastDeadline) {
325
+ return { ...ctx, decision: 'deferred-busy', reason: 'topic busy, within safe-point deadline' };
326
+ }
327
+ return { ...ctx, decision: 'transfer', reason: `I am the live owner, pin → ${pin.preferredMachine} → would transfer` };
328
+ }
329
+ if (pin.preferredMachine === self) {
330
+ const byId = new Map(machines.map((m) => [m.machineId, m]));
331
+ const ownerView = owner ? byId.get(owner) : undefined;
332
+ const ownerProvablyDead = !!ownerView && !ownerView.online
333
+ && (now - ownerView.lastSeenMs) >= (this.d.deathEvidenceMs ?? DEFAULT_DEATH_EVIDENCE_MS);
334
+ const ownerUnknown = !!owner && !ownerView;
335
+ const onlineCount = machines.filter((m) => m.online).length;
336
+ const inQuorum = machines.length <= 2 || onlineCount * 2 > machines.length;
337
+ if ((ownerProvablyDead || ownerUnknown) && inQuorum) {
338
+ return { ...ctx, decision: 'force-claim', reason: 'pin names me + owner provably dead/unknown + in quorum' };
339
+ }
340
+ return { ...ctx, decision: 'deferred-no-evidence', reason: `pin names me but owner ${owner} is alive/unproven-dead (online=${ownerView?.online ?? 'unknown'}) — waiting for its own Case-A transfer` };
341
+ }
342
+ return { ...ctx, decision: 'not-my-move', reason: 'neither owner nor pin target this tick' };
343
+ }
344
+ /** Reconciler status (Observable Intelligence): last tick report + when, plus the
345
+ * live enabled/dryRun gate and machine-count the reconciler actually sees. */
346
+ status() {
347
+ let machinesCount = 0;
348
+ try {
349
+ machinesCount = this.d.machines().length;
350
+ }
351
+ catch { /* best-effort */ }
352
+ return {
353
+ enabled: (() => { try {
354
+ return !!this.d.enabled();
355
+ }
356
+ catch {
357
+ return false;
358
+ } })(),
359
+ dryRun: (() => { try {
360
+ return !!this.d.dryRun();
361
+ }
362
+ catch {
363
+ return true;
364
+ } })(),
365
+ lastTickAt: this.lastTickAtMs ? new Date(this.lastTickAtMs).toISOString() : null,
366
+ lastReport: this.lastReport,
367
+ machinesCount,
368
+ selfMachineId: this.d.selfMachineId,
369
+ };
370
+ }
201
371
  }
202
372
  //# sourceMappingURL=OwnershipReconciler.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"OwnershipReconciler.js","sourceRoot":"","sources":["../../src/core/OwnershipReconciler.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"OwnershipReconciler.js","sourceRoot":"","sources":["../../src/core/OwnershipReconciler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * TopicPinReplicatedStore — replicate the user's topic PIN (move-intent) across the
3
+ * agent's own machines so the OWNING machine's WS1.3 OwnershipReconciler can see "you
4
+ * are pinned away" and start the cooperative transfer (Fix #2 of the cross-machine
5
+ * stuck-move fix; spec docs/specs/cross-machine-reconciler-convergence.md).
6
+ *
7
+ * It rides the SAME generic WS2 replicated-record machinery the memory/PII stores use
8
+ * (ReplicatedRecordEmitter + ReplicatedKindRegistry + the HLC envelope), so it inherits
9
+ * HLC ordering (NEVER wall-clock — the clock-skew class this whole work fixes), the
10
+ * provenance envelope, tombstone-on-clear, and per-kind retention/rate-cap. But a PIN is
11
+ * NOT PII — it is just `{topic, preferredMachine, pinned}` — so this consumer is a LEAN
12
+ * analog of EvolutionActionsReplicatedStore (no disclosure-minimization projection, no
13
+ * divergent-value union; HLC-highest-wins is sufficient for a move-intent).
14
+ *
15
+ * CRITICAL POSTURE (Findings C1/AD4/LA1): a replicated pin is ADVISORY. It lands in this
16
+ * SEPARATE store, never the authoritative local TopicPlacementPinStore. The reconciler
17
+ * consults it as VALIDATED move-intent (known + online target) that can trigger ONLY the
18
+ * owner's OWN cooperative transfer — never a force-claim / seat-steal. Under the declared
19
+ * single-agent threat model the residual hazard is a STALE/CORRUPT peer stream, which HLC
20
+ * ordering + known-machine validation + freshness defend against.
21
+ */
22
+ import type { StoreFieldSchema } from './ReplicatedRecordEnvelope.js';
23
+ import type { HlcTimestamp } from './HybridLogicalClock.js';
24
+ /** The JournalKind string this store rides (the dual-registry's dynamic half; the static
25
+ * half is CoherenceJournal.JOURNAL_KINDS, which now lists 'topic-pin-record'). */
26
+ export declare const TOPIC_PIN_RECORD_KIND = "topic-pin-record";
27
+ /** The store key used by the emitter dark-gate + the rollback-unmerge getByStore wiring. */
28
+ export declare const TOPIC_PIN_STORE_KEY = "topicPins";
29
+ /** recordKey = the cross-machine IDENTITY SURFACE = the topic id as a string (a pin is
30
+ * per-topic; a re-pin to a different machine is the SAME key with a newer HLC). */
31
+ export declare function deriveTopicPinRecordKey(topic: number | string): string | null;
32
+ export declare const topicPinRecordStoreSchema: StoreFieldSchema;
33
+ /** The dual-registry registration (mirrors EVOLUTION_ACTION_KIND_REGISTRATION). Registration
34
+ * is INERT — emission stays gated behind the store's enable flag (ws13PinReplicate). */
35
+ export declare const TOPIC_PIN_KIND_REGISTRATION: {
36
+ readonly kind: "topic-pin-record";
37
+ readonly store: "topicPins";
38
+ readonly schema: StoreFieldSchema;
39
+ };
40
+ export declare function topicPinContributingKinds(): string[];
41
+ /** Build a PUT (set-pin) record's data, given the emitter-supplied envelope inputs. */
42
+ export declare function buildTopicPinPut(topic: number, preferredMachine: string, pinned: boolean): (hlc: HlcTimestamp, origin: string, observed?: HlcTimestamp) => Record<string, unknown> | null;
43
+ /** Build a TOMBSTONE (clear-pin) record's data. */
44
+ export declare function buildTopicPinTombstone(topic: number, deletedAt: string): (hlc: HlcTimestamp, origin: string, observed?: HlcTimestamp) => Record<string, unknown> | null;
45
+ /** Total order over HLC timestamps: physical, then logical, then node (the §7
46
+ * tie-breaker of last resort). >0 ⇒ a is newer than b. */
47
+ export declare function compareHlc(a: HlcTimestamp, b: HlcTimestamp): number;
48
+ /** A merged, advisory replicated pin for one topic (READ-ONLY; never written to the
49
+ * authoritative local pin store). `origin` is the machine that asserted it. */
50
+ export interface MergedReplicatedPin {
51
+ topic: number;
52
+ preferredMachine: string;
53
+ pinned: boolean;
54
+ origin: string;
55
+ /** The winning HLC — used by the reconciler to HLC-order against the LOCAL pin. */
56
+ hlc: HlcTimestamp;
57
+ }
58
+ /**
59
+ * Collapse replicated `topic-pin-record` entries to ONE advisory pin per topic: the
60
+ * HIGHEST-HLC record wins (skew-proof). A winning TOMBSTONE (op:'delete') resolves to
61
+ * "no pin" for that topic (the clear superseded the set). A `pinned:false` PUT likewise
62
+ * yields no effective pin. Input entries are the already-envelope-validated records.
63
+ */
64
+ export declare function mergeUnionToPins(entries: Array<{
65
+ data: Record<string, unknown>;
66
+ origin: string;
67
+ }>, hlcCompare: (a: HlcTimestamp, b: HlcTimestamp) => number): Map<number, MergedReplicatedPin>;
68
+ //# sourceMappingURL=TopicPinReplicatedStore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TopicPinReplicatedStore.d.ts","sourceRoot":"","sources":["../../src/core/TopicPinReplicatedStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAsC,MAAM,+BAA+B,CAAC;AAC1G,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAE5D;mFACmF;AACnF,eAAO,MAAM,qBAAqB,qBAAqB,CAAC;AACxD,4FAA4F;AAC5F,eAAO,MAAM,mBAAmB,cAAc,CAAC;AAS/C;oFACoF;AACpF,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAI7E;AAED,eAAO,MAAM,yBAAyB,EAAE,gBAuBvC,CAAC;AAEF;yFACyF;AACzF,eAAO,MAAM,2BAA2B;;;;CAI9B,CAAC;AAEX,wBAAgB,yBAAyB,IAAI,MAAM,EAAE,CAEpD;AAED,uFAAuF;AACvF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,IAC/E,KAAK,YAAY,EAAE,QAAQ,MAAM,EAAE,WAAW,YAAY,KAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CASpG;AAED,mDAAmD;AACnD,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,IAC7D,KAAK,YAAY,EAAE,QAAQ,MAAM,EAAE,WAAW,YAAY,KAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CASpG;AAED;2DAC2D;AAC3D,wBAAgB,UAAU,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,GAAG,MAAM,CAInE;AAED;gFACgF;AAChF,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,mFAAmF;IACnF,GAAG,EAAE,YAAY,CAAC;CACnB;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,EACjE,UAAU,EAAE,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,KAAK,MAAM,GACvD,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAsBlC"}