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.
- 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/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/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/devGatedFeatures.d.ts.map +1 -1
- package/dist/core/devGatedFeatures.js +6 -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/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 +33 -0
- 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.699.md +31 -0
- 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
|
-
|
|
70
|
-
|
|
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
|
|
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
|
|
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":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;
|
|
1
|
+
{"version":3,"file":"OwnershipApplier.js","sourceRoot":"","sources":["../../src/core/OwnershipApplier.ts"],"names":[],"mappings":"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"}
|
|
@@ -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,
|
|
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"}
|