instar 1.3.697 → 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.
- package/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +81 -7
- package/dist/commands/server.js.map +1 -1
- package/dist/config/ConfigDefaults.d.ts.map +1 -1
- package/dist/config/ConfigDefaults.js +9 -0
- package/dist/config/ConfigDefaults.js.map +1 -1
- package/dist/core/CoherenceJournal.d.ts +10 -1
- package/dist/core/CoherenceJournal.d.ts.map +1 -1
- package/dist/core/CoherenceJournal.js +31 -3
- package/dist/core/CoherenceJournal.js.map +1 -1
- package/dist/core/MachinePoolRegistry.d.ts +13 -0
- package/dist/core/MachinePoolRegistry.d.ts.map +1 -1
- package/dist/core/MachinePoolRegistry.js +22 -3
- package/dist/core/MachinePoolRegistry.js.map +1 -1
- package/dist/core/MessagingToneGate.d.ts +38 -0
- package/dist/core/MessagingToneGate.d.ts.map +1 -1
- package/dist/core/MessagingToneGate.js +30 -3
- package/dist/core/MessagingToneGate.js.map +1 -1
- package/dist/core/OwnershipApplier.d.ts +21 -0
- package/dist/core/OwnershipApplier.d.ts.map +1 -1
- package/dist/core/OwnershipApplier.js +60 -5
- package/dist/core/OwnershipApplier.js.map +1 -1
- package/dist/core/OwnershipReconciler.d.ts +70 -1
- package/dist/core/OwnershipReconciler.d.ts.map +1 -1
- package/dist/core/OwnershipReconciler.js +177 -7
- package/dist/core/OwnershipReconciler.js.map +1 -1
- package/dist/core/TopicPinReplicatedStore.d.ts +68 -0
- package/dist/core/TopicPinReplicatedStore.d.ts.map +1 -0
- package/dist/core/TopicPinReplicatedStore.js +148 -0
- package/dist/core/TopicPinReplicatedStore.js.map +1 -0
- package/dist/core/TopicPlacementPinStore.d.ts +20 -2
- package/dist/core/TopicPlacementPinStore.d.ts.map +1 -1
- package/dist/core/TopicPlacementPinStore.js +5 -3
- package/dist/core/TopicPlacementPinStore.js.map +1 -1
- package/dist/core/ask-when-authorized.d.ts +32 -0
- package/dist/core/ask-when-authorized.d.ts.map +1 -0
- package/dist/core/ask-when-authorized.js +73 -0
- package/dist/core/ask-when-authorized.js.map +1 -0
- package/dist/core/bias-to-action-telemetry.d.ts +35 -0
- package/dist/core/bias-to-action-telemetry.d.ts.map +1 -0
- package/dist/core/bias-to-action-telemetry.js +40 -0
- package/dist/core/bias-to-action-telemetry.js.map +1 -0
- package/dist/core/devGatedFeatures.d.ts.map +1 -1
- package/dist/core/devGatedFeatures.js +12 -0
- package/dist/core/devGatedFeatures.js.map +1 -1
- package/dist/core/ownershipApplierWiring.d.ts +5 -0
- package/dist/core/ownershipApplierWiring.d.ts.map +1 -1
- package/dist/core/ownershipApplierWiring.js +3 -0
- package/dist/core/ownershipApplierWiring.js.map +1 -1
- package/dist/core/standing-authorization.d.ts +72 -0
- package/dist/core/standing-authorization.d.ts.map +1 -0
- package/dist/core/standing-authorization.js +130 -0
- package/dist/core/standing-authorization.js.map +1 -0
- package/dist/core/types.d.ts +30 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/messaging/TelegramAdapter.d.ts +12 -0
- package/dist/messaging/TelegramAdapter.d.ts.map +1 -1
- package/dist/messaging/TelegramAdapter.js +8 -0
- package/dist/messaging/TelegramAdapter.js.map +1 -1
- package/dist/server/AgentServer.d.ts +2 -0
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +1 -0
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/routes.d.ts +2 -0
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +132 -1
- package/dist/server/routes.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +47 -47
- package/upgrades/1.3.698.md +90 -0
- package/upgrades/1.3.699.md +31 -0
- package/upgrades/side-effects/bias-to-action.md +126 -0
- package/upgrades/side-effects/cross-machine-reconciler-convergence.md +56 -0
|
@@ -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,
|
|
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.
|
|
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
|
-
|
|
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"}
|
|
@@ -0,0 +1,148 @@
|
|
|
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
|
+
/** The JournalKind string this store rides (the dual-registry's dynamic half; the static
|
|
23
|
+
* half is CoherenceJournal.JOURNAL_KINDS, which now lists 'topic-pin-record'). */
|
|
24
|
+
export const TOPIC_PIN_RECORD_KIND = 'topic-pin-record';
|
|
25
|
+
/** The store key used by the emitter dark-gate + the rollback-unmerge getByStore wiring. */
|
|
26
|
+
export const TOPIC_PIN_STORE_KEY = 'topicPins';
|
|
27
|
+
/** Machine-id charset clamp (consistent with sanitizeMachineId elsewhere): a peer-supplied
|
|
28
|
+
* preferredMachine that is not a plain id is rejected (it flows into placement decisions). */
|
|
29
|
+
const MACHINE_ID_RE = /^[\w-]{1,64}$/;
|
|
30
|
+
/** The store-owned fields (for the registry's unknown-field counting). */
|
|
31
|
+
const TOPIC_PIN_KNOWN_FIELDS = ['topic', 'preferredMachine', 'pinned', 'deletedAt'];
|
|
32
|
+
/** recordKey = the cross-machine IDENTITY SURFACE = the topic id as a string (a pin is
|
|
33
|
+
* per-topic; a re-pin to a different machine is the SAME key with a newer HLC). */
|
|
34
|
+
export function deriveTopicPinRecordKey(topic) {
|
|
35
|
+
const n = typeof topic === 'number' ? topic : Number(topic);
|
|
36
|
+
if (!Number.isFinite(n))
|
|
37
|
+
return null;
|
|
38
|
+
return String(n);
|
|
39
|
+
}
|
|
40
|
+
export const topicPinRecordStoreSchema = {
|
|
41
|
+
knownFields: TOPIC_PIN_KNOWN_FIELDS,
|
|
42
|
+
pathSensitiveFields: ['preferredMachine'],
|
|
43
|
+
validate(raw, ctx) {
|
|
44
|
+
if (raw.op === 'delete') {
|
|
45
|
+
// Tombstone (the CLEAR): only deletedAt is a legal store field; the recordKey + hlc +
|
|
46
|
+
// op (envelope, already validated) carry the suppression.
|
|
47
|
+
const deletedAt = typeof raw.deletedAt === 'string' ? raw.deletedAt : undefined;
|
|
48
|
+
for (const k of Object.keys(raw)) {
|
|
49
|
+
if (k === 'op' || k === 'deletedAt')
|
|
50
|
+
continue;
|
|
51
|
+
if (TOPIC_PIN_KNOWN_FIELDS.includes(k))
|
|
52
|
+
ctx.countDroppedField();
|
|
53
|
+
}
|
|
54
|
+
return deletedAt !== undefined ? { deletedAt } : {};
|
|
55
|
+
}
|
|
56
|
+
// PUT (set the pin). topic — finite number; preferredMachine — charset-clamped machine
|
|
57
|
+
// id; pinned — strict boolean. A malformed field rejects the whole record (quarantined
|
|
58
|
+
// by the envelope machinery, never silently dropped).
|
|
59
|
+
const topic = typeof raw.topic === 'number' && Number.isFinite(raw.topic) ? raw.topic : null;
|
|
60
|
+
if (topic === null)
|
|
61
|
+
return null;
|
|
62
|
+
if (typeof raw.preferredMachine !== 'string' || !MACHINE_ID_RE.test(raw.preferredMachine))
|
|
63
|
+
return null;
|
|
64
|
+
if (typeof raw.pinned !== 'boolean')
|
|
65
|
+
return null;
|
|
66
|
+
return { topic, preferredMachine: raw.preferredMachine, pinned: raw.pinned };
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
/** The dual-registry registration (mirrors EVOLUTION_ACTION_KIND_REGISTRATION). Registration
|
|
70
|
+
* is INERT — emission stays gated behind the store's enable flag (ws13PinReplicate). */
|
|
71
|
+
export const TOPIC_PIN_KIND_REGISTRATION = {
|
|
72
|
+
kind: TOPIC_PIN_RECORD_KIND,
|
|
73
|
+
store: TOPIC_PIN_STORE_KEY,
|
|
74
|
+
schema: topicPinRecordStoreSchema,
|
|
75
|
+
};
|
|
76
|
+
export function topicPinContributingKinds() {
|
|
77
|
+
return [TOPIC_PIN_RECORD_KIND];
|
|
78
|
+
}
|
|
79
|
+
/** Build a PUT (set-pin) record's data, given the emitter-supplied envelope inputs. */
|
|
80
|
+
export function buildTopicPinPut(topic, preferredMachine, pinned) {
|
|
81
|
+
return (hlc, origin, observed) => {
|
|
82
|
+
const recordKey = deriveTopicPinRecordKey(topic);
|
|
83
|
+
if (recordKey === null || !MACHINE_ID_RE.test(preferredMachine))
|
|
84
|
+
return null;
|
|
85
|
+
return {
|
|
86
|
+
topic, preferredMachine, pinned,
|
|
87
|
+
recordKey, hlc, op: 'put', origin,
|
|
88
|
+
...(observed !== undefined ? { observed } : {}),
|
|
89
|
+
};
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
/** Build a TOMBSTONE (clear-pin) record's data. */
|
|
93
|
+
export function buildTopicPinTombstone(topic, deletedAt) {
|
|
94
|
+
return (hlc, origin, observed) => {
|
|
95
|
+
const recordKey = deriveTopicPinRecordKey(topic);
|
|
96
|
+
if (recordKey === null)
|
|
97
|
+
return null;
|
|
98
|
+
return {
|
|
99
|
+
deletedAt,
|
|
100
|
+
recordKey, hlc, op: 'delete', origin,
|
|
101
|
+
...(observed !== undefined ? { observed } : {}),
|
|
102
|
+
};
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/** Total order over HLC timestamps: physical, then logical, then node (the §7
|
|
106
|
+
* tie-breaker of last resort). >0 ⇒ a is newer than b. */
|
|
107
|
+
export function compareHlc(a, b) {
|
|
108
|
+
if (a.physical !== b.physical)
|
|
109
|
+
return a.physical - b.physical;
|
|
110
|
+
if (a.logical !== b.logical)
|
|
111
|
+
return a.logical - b.logical;
|
|
112
|
+
return a.node < b.node ? -1 : a.node > b.node ? 1 : 0;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Collapse replicated `topic-pin-record` entries to ONE advisory pin per topic: the
|
|
116
|
+
* HIGHEST-HLC record wins (skew-proof). A winning TOMBSTONE (op:'delete') resolves to
|
|
117
|
+
* "no pin" for that topic (the clear superseded the set). A `pinned:false` PUT likewise
|
|
118
|
+
* yields no effective pin. Input entries are the already-envelope-validated records.
|
|
119
|
+
*/
|
|
120
|
+
export function mergeUnionToPins(entries, hlcCompare) {
|
|
121
|
+
// First pass: pick the highest-HLC record per recordKey (put OR delete).
|
|
122
|
+
const winner = new Map();
|
|
123
|
+
for (const e of entries) {
|
|
124
|
+
const hlc = e.data.hlc;
|
|
125
|
+
const recordKey = typeof e.data.recordKey === 'string' ? e.data.recordKey : null;
|
|
126
|
+
if (!hlc || recordKey === null)
|
|
127
|
+
continue;
|
|
128
|
+
const cur = winner.get(recordKey);
|
|
129
|
+
if (!cur || hlcCompare(hlc, cur.hlc) > 0)
|
|
130
|
+
winner.set(recordKey, { data: e.data, origin: e.origin, hlc });
|
|
131
|
+
}
|
|
132
|
+
// Second pass: a winning delete/pinned:false → no effective pin.
|
|
133
|
+
const out = new Map();
|
|
134
|
+
for (const [recordKey, w] of winner) {
|
|
135
|
+
if (w.data.op === 'delete')
|
|
136
|
+
continue;
|
|
137
|
+
const pinned = w.data.pinned === true;
|
|
138
|
+
if (!pinned)
|
|
139
|
+
continue;
|
|
140
|
+
const topic = Number(recordKey);
|
|
141
|
+
const preferredMachine = typeof w.data.preferredMachine === 'string' ? w.data.preferredMachine : '';
|
|
142
|
+
if (!Number.isFinite(topic) || !MACHINE_ID_RE.test(preferredMachine))
|
|
143
|
+
continue;
|
|
144
|
+
out.set(topic, { topic, preferredMachine, pinned: true, origin: w.origin, hlc: w.hlc });
|
|
145
|
+
}
|
|
146
|
+
return out;
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=TopicPinReplicatedStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TopicPinReplicatedStore.js","sourceRoot":"","sources":["../../src/core/TopicPinReplicatedStore.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,6 +4,18 @@ export interface TopicPin {
|
|
|
4
4
|
preferredMachine: string;
|
|
5
5
|
pinned: boolean;
|
|
6
6
|
updatedAt: string;
|
|
7
|
+
/**
|
|
8
|
+
* Cross-machine convergence (Fix #2 / Finding N3): the HLC stamped when this pin was
|
|
9
|
+
* set, so the reconciler can HLC-ORDER the local pin against a replicated advisory pin
|
|
10
|
+
* (a skew-PROOF comparison, never wall-clock). Absent on pre-Fix-#2 pins → the reconciler
|
|
11
|
+
* derives a fallback HLC from `updatedAt` on read (the documented migration). Structural
|
|
12
|
+
* type (not the HlcTimestamp import) to keep this low-level store dependency-free.
|
|
13
|
+
*/
|
|
14
|
+
hlc?: {
|
|
15
|
+
physical: number;
|
|
16
|
+
logical: number;
|
|
17
|
+
node: string;
|
|
18
|
+
};
|
|
7
19
|
}
|
|
8
20
|
export interface TopicPlacementPinStoreDeps {
|
|
9
21
|
/** File the pins persist to (JSON). */
|
|
@@ -18,8 +30,14 @@ export declare class TopicPlacementPinStore {
|
|
|
18
30
|
constructor(deps: TopicPlacementPinStoreDeps);
|
|
19
31
|
private load;
|
|
20
32
|
private persist;
|
|
21
|
-
/** Pin a topic to a machine (a hard pin). Idempotent; refreshes `updatedAt`.
|
|
22
|
-
|
|
33
|
+
/** Pin a topic to a machine (a hard pin). Idempotent; refreshes `updatedAt`.
|
|
34
|
+
* `hlc` (Fix #2) is the skew-proof ordering stamp; pass the same HLC that the
|
|
35
|
+
* replicated `topic-pin-record` carried so local and replicated pins compare cleanly. */
|
|
36
|
+
set(sessionKey: string, preferredMachine: string, pinned?: boolean, hlc?: {
|
|
37
|
+
physical: number;
|
|
38
|
+
logical: number;
|
|
39
|
+
node: string;
|
|
40
|
+
}): void;
|
|
23
41
|
/** The current pin for a topic, or null if unpinned. */
|
|
24
42
|
get(sessionKey: string): TopicPin | null;
|
|
25
43
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TopicPlacementPinStore.d.ts","sourceRoot":"","sources":["../../src/core/TopicPlacementPinStore.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAE7D,wEAAwE;AACxE,MAAM,WAAW,QAAQ;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"TopicPlacementPinStore.d.ts","sourceRoot":"","sources":["../../src/core/TopicPlacementPinStore.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAE7D,wEAAwE;AACxE,MAAM,WAAW,QAAQ;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;;OAMG;IACH,GAAG,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CAC3D;AAED,MAAM,WAAW,0BAA0B;IACzC,uCAAuC;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CAClB;AAED,qBAAa,sBAAsB;IACjC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAA6B;IAC/C,OAAO,CAAC,IAAI,CAAgC;IAC5C,OAAO,CAAC,MAAM,CAAS;gBAEX,IAAI,EAAE,0BAA0B;IAI5C,OAAO,CAAC,IAAI;IAeZ,OAAO,CAAC,OAAO;IAQf;;8FAE0F;IAC1F,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,UAAO,EAAE,GAAG,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAOjI,wDAAwD;IACxD,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI;IAKxC;;;OAGG;IACH,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAK/D,+GAA+G;IAC/G,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAOlD,oFAAoF;IACpF,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAQ/B,yDAAyD;IACzD,GAAG,IAAI,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC;CAIhC"}
|
|
@@ -50,11 +50,13 @@ export class TopicPlacementPinStore {
|
|
|
50
50
|
fs.writeFileSync(tmp, JSON.stringify({ pins: this.pins }, null, 2));
|
|
51
51
|
fs.renameSync(tmp, this.d.filePath); // atomic swap
|
|
52
52
|
}
|
|
53
|
-
/** Pin a topic to a machine (a hard pin). Idempotent; refreshes `updatedAt`.
|
|
54
|
-
|
|
53
|
+
/** Pin a topic to a machine (a hard pin). Idempotent; refreshes `updatedAt`.
|
|
54
|
+
* `hlc` (Fix #2) is the skew-proof ordering stamp; pass the same HLC that the
|
|
55
|
+
* replicated `topic-pin-record` carried so local and replicated pins compare cleanly. */
|
|
56
|
+
set(sessionKey, preferredMachine, pinned = true, hlc) {
|
|
55
57
|
this.load();
|
|
56
58
|
const now = (this.d.now ?? (() => new Date()))().toISOString();
|
|
57
|
-
this.pins[sessionKey] = { preferredMachine, pinned, updatedAt: now };
|
|
59
|
+
this.pins[sessionKey] = { preferredMachine, pinned, updatedAt: now, ...(hlc ? { hlc } : {}) };
|
|
58
60
|
this.persist();
|
|
59
61
|
}
|
|
60
62
|
/** The current pin for a topic, or null if unpinned. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TopicPlacementPinStore.js","sourceRoot":"","sources":["../../src/core/TopicPlacementPinStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"TopicPlacementPinStore.js","sourceRoot":"","sources":["../../src/core/TopicPlacementPinStore.ts"],"names":[],"mappings":"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"}
|