instar 1.3.511 → 1.3.513
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 +168 -2
- package/dist/commands/server.js.map +1 -1
- package/dist/config/ConfigDefaults.d.ts.map +1 -1
- package/dist/config/ConfigDefaults.js +42 -0
- package/dist/config/ConfigDefaults.js.map +1 -1
- package/dist/core/CoherenceJournal.d.ts +31 -1
- package/dist/core/CoherenceJournal.d.ts.map +1 -1
- package/dist/core/CoherenceJournal.js +49 -2
- package/dist/core/CoherenceJournal.js.map +1 -1
- package/dist/core/JournalSyncApplier.d.ts.map +1 -1
- package/dist/core/JournalSyncApplier.js +18 -0
- package/dist/core/JournalSyncApplier.js.map +1 -1
- package/dist/core/MeshRpc.d.ts +6 -0
- package/dist/core/MeshRpc.d.ts.map +1 -1
- package/dist/core/MeshRpc.js +1 -0
- package/dist/core/MeshRpc.js.map +1 -1
- package/dist/core/PeerPresencePuller.d.ts +19 -0
- package/dist/core/PeerPresencePuller.d.ts.map +1 -1
- package/dist/core/PeerPresencePuller.js +7 -0
- package/dist/core/PeerPresencePuller.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +57 -0
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/PreferencesManager.d.ts +34 -0
- package/dist/core/PreferencesManager.d.ts.map +1 -1
- package/dist/core/PreferencesManager.js +74 -0
- package/dist/core/PreferencesManager.js.map +1 -1
- package/dist/core/PreferencesSync.d.ts +167 -0
- package/dist/core/PreferencesSync.d.ts.map +1 -0
- package/dist/core/PreferencesSync.js +307 -0
- package/dist/core/PreferencesSync.js.map +1 -0
- package/dist/core/devGatedFeatures.d.ts.map +1 -1
- package/dist/core/devGatedFeatures.js +5 -0
- package/dist/core/devGatedFeatures.js.map +1 -1
- package/dist/core/types.d.ts +34 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/monitoring/GreenPrAutoMerger.d.ts +188 -0
- package/dist/monitoring/GreenPrAutoMerger.d.ts.map +1 -0
- package/dist/monitoring/GreenPrAutoMerger.js +393 -0
- package/dist/monitoring/GreenPrAutoMerger.js.map +1 -0
- package/dist/monitoring/GuardLatchStore.d.ts +134 -0
- package/dist/monitoring/GuardLatchStore.d.ts.map +1 -0
- package/dist/monitoring/GuardLatchStore.js +255 -0
- package/dist/monitoring/GuardLatchStore.js.map +1 -0
- package/dist/monitoring/MergeRunner.d.ts +126 -0
- package/dist/monitoring/MergeRunner.d.ts.map +1 -0
- package/dist/monitoring/MergeRunner.js +296 -0
- package/dist/monitoring/MergeRunner.js.map +1 -0
- package/dist/monitoring/floorDriftCanary.d.ts +88 -0
- package/dist/monitoring/floorDriftCanary.d.ts.map +1 -0
- package/dist/monitoring/floorDriftCanary.js +89 -0
- package/dist/monitoring/floorDriftCanary.js.map +1 -0
- package/dist/monitoring/greenPrAutomergeWiring.d.ts +73 -0
- package/dist/monitoring/greenPrAutomergeWiring.d.ts.map +1 -0
- package/dist/monitoring/greenPrAutomergeWiring.js +273 -0
- package/dist/monitoring/greenPrAutomergeWiring.js.map +1 -0
- package/dist/monitoring/greenPrLogic.d.ts +121 -0
- package/dist/monitoring/greenPrLogic.d.ts.map +1 -0
- package/dist/monitoring/greenPrLogic.js +198 -0
- package/dist/monitoring/greenPrLogic.js.map +1 -0
- package/dist/monitoring/guardManifest.d.ts.map +1 -1
- package/dist/monitoring/guardManifest.js +12 -0
- package/dist/monitoring/guardManifest.js.map +1 -1
- package/dist/scaffold/templates.d.ts.map +1 -1
- package/dist/scaffold/templates.js +1 -0
- package/dist/scaffold/templates.js.map +1 -1
- package/dist/server/AgentServer.d.ts +5 -0
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +3 -0
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/CapabilityIndex.d.ts.map +1 -1
- package/dist/server/CapabilityIndex.js +16 -0
- package/dist/server/CapabilityIndex.js.map +1 -1
- package/dist/server/routes.d.ts +10 -0
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +137 -1
- package/dist/server/routes.js.map +1 -1
- package/dist/server/stopGate.d.ts +45 -0
- package/dist/server/stopGate.d.ts.map +1 -1
- package/dist/server/stopGate.js +74 -0
- package/dist/server/stopGate.js.map +1 -1
- package/package.json +1 -1
- package/scripts/safe-merge.mjs +449 -59
- package/src/data/builtin-manifest.json +64 -64
- package/src/scaffold/templates.ts +1 -0
- package/upgrades/1.3.512.md +65 -0
- package/upgrades/1.3.513.md +61 -0
- package/upgrades/side-effects/green-pr-automerge-enforcement.md +171 -0
- package/upgrades/side-effects/multi-machine-seamlessness-ws21-preferences-pool.md +116 -0
|
@@ -54,11 +54,30 @@ export interface PreferenceEntry {
|
|
|
54
54
|
* SIGNAL-ONLY: a match never blocks/alters the outbound message.
|
|
55
55
|
*/
|
|
56
56
|
violationPattern?: string;
|
|
57
|
+
/**
|
|
58
|
+
* WS2.1 cross-machine replication (additive). The store `replicationSeq` at
|
|
59
|
+
* this entry's most recent upsert — the delta-window key the sync serve side
|
|
60
|
+
* pages on. Absent on a legacy entry ⇒ backfilled to 1 (serves on a from-0
|
|
61
|
+
* pull). Local-only bookkeeping; never part of the injected session block.
|
|
62
|
+
*/
|
|
63
|
+
lastMutatedSeq?: number;
|
|
57
64
|
}
|
|
58
65
|
/** The full on-disk store shape. */
|
|
59
66
|
export interface PreferencesStore {
|
|
60
67
|
schemaVersion: number;
|
|
61
68
|
preferences: PreferenceEntry[];
|
|
69
|
+
/**
|
|
70
|
+
* WS2.1 cross-machine replication (additive). Monotonic per-machine mutation
|
|
71
|
+
* counter — each `recordPreference` upsert bumps it and stamps the entry's
|
|
72
|
+
* `lastMutatedSeq`. Absent on a legacy store ⇒ seeded to 1 on next read.
|
|
73
|
+
*/
|
|
74
|
+
replicationSeq?: number;
|
|
75
|
+
/**
|
|
76
|
+
* WS2.1 — opaque per-store incarnation. Re-minted when a restore rewinds the
|
|
77
|
+
* store below its high-water seq, so replica peers re-pull wholesale instead
|
|
78
|
+
* of stranding behind a backward seq. Absent on a legacy store ⇒ minted.
|
|
79
|
+
*/
|
|
80
|
+
storeIncarnation?: string;
|
|
62
81
|
}
|
|
63
82
|
/** Input payload for `recordPreference()`. */
|
|
64
83
|
export interface RecordPreferencePayload {
|
|
@@ -136,5 +155,20 @@ export declare class PreferencesManager {
|
|
|
136
155
|
};
|
|
137
156
|
/** Atomic write: temp file + fsync + rename. */
|
|
138
157
|
private writeAtomic;
|
|
158
|
+
/**
|
|
159
|
+
* WS2.1 — the replication advert ({ incarnation, replicationSeq }) the
|
|
160
|
+
* `preferences-sync` serve side answers with. Sourced from the on-disk store
|
|
161
|
+
* (read() seeds both fields), so a fresh/legacy store yields a valid advert.
|
|
162
|
+
*/
|
|
163
|
+
getReplicationAdvert(): {
|
|
164
|
+
incarnation: string;
|
|
165
|
+
replicationSeq: number;
|
|
166
|
+
};
|
|
167
|
+
/**
|
|
168
|
+
* WS2.1 — the OWN preferences with their replication seqs, for the sync serve
|
|
169
|
+
* side (buildPreferencesSyncPage). Never includes replicas. Each entry's
|
|
170
|
+
* `lastMutatedSeq` is backfilled to 1 by read() when absent.
|
|
171
|
+
*/
|
|
172
|
+
getAllForSync(): PreferenceEntry[];
|
|
139
173
|
}
|
|
140
174
|
//# sourceMappingURL=PreferencesManager.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PreferencesManager.d.ts","sourceRoot":"","sources":["../../src/core/PreferencesManager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;
|
|
1
|
+
{"version":3,"file":"PreferencesManager.d.ts","sourceRoot":"","sources":["../../src/core/PreferencesManager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAQH,yEAAyE;AACzE,eAAO,MAAM,0BAA0B,IAAI,CAAC;AAE5C,qFAAqF;AACrF,MAAM,MAAM,oBAAoB,GAAG,iBAAiB,CAAC;AAErD,+EAA+E;AAC/E,MAAM,WAAW,eAAe;IAC9B,qFAAqF;IACrF,QAAQ,EAAE,MAAM,CAAC;IACjB,gEAAgE;IAChE,UAAU,EAAE,oBAAoB,CAAC;IACjC,oEAAoE;IACpE,SAAS,EAAE,MAAM,CAAC;IAClB,uEAAuE;IACvE,UAAU,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,UAAU,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;;;;;;;OAWG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,oCAAoC;AACpC,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,eAAe,EAAE,CAAC;IAC/B;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,8CAA8C;AAC9C,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,sDAAsD;IACtD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qCAAqC;IACrC,UAAU,CAAC,EAAE,oBAAoB,CAAC;IAClC,iEAAiE;IACjE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,wCAAwC;AACxC,MAAM,WAAW,uBAAuB;IACtC;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AA6BD;;;;;;;;;GASG;AACH,wBAAgB,gCAAgC,CAC9C,KAAK,EAAE,gBAAgB,EACvB,QAAQ,SAAO,GACd,MAAM,CAmBR;AAID,qBAAa,kBAAkB;IAGjB,OAAO,CAAC,QAAQ;IAF5B,OAAO,CAAC,eAAe,CAAS;gBAEZ,QAAQ,EAAE,MAAM;IAIpC,qEAAqE;IACrE,OAAO,IAAI,MAAM;IAIjB,+CAA+C;IAC/C,MAAM,IAAI,OAAO;IAIjB;;;;OAIG;IACH,IAAI,IAAI,gBAAgB;IAqExB;;;;;;;;;;OAUG;IACH,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,EAAE,KAAK,GAAE,uBAA4B,GAAG,eAAe;IA8DxG;;;;;OAKG;IACH,cAAc,CAAC,QAAQ,SAAO,GAAG;QAC/B,OAAO,EAAE,OAAO,CAAC;QACjB,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;KACf;IAUD,gDAAgD;IAChD,OAAO,CAAC,WAAW;IAiCnB;;;;OAIG;IACH,oBAAoB,IAAI;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAE;IAQvE;;;;OAIG;IACH,aAAa,IAAI,eAAe,EAAE;CAGnC"}
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
* so the agent always SEES them. There is no enforcement gate. (The blocking
|
|
24
24
|
* idea was explicitly rejected by the user — see spec frontmatter.)
|
|
25
25
|
*/
|
|
26
|
+
import { randomUUID } from 'node:crypto';
|
|
26
27
|
import fs from 'node:fs';
|
|
27
28
|
import path from 'node:path';
|
|
28
29
|
// ── Types ────────────────────────────────────────────────────────────
|
|
@@ -142,11 +143,34 @@ export class PreferencesManager {
|
|
|
142
143
|
if (typeof p.violationPattern === 'string' && p.violationPattern.trim().length > 0) {
|
|
143
144
|
entry.violationPattern = p.violationPattern;
|
|
144
145
|
}
|
|
146
|
+
// WS2.1: preserve the replication seq; a legacy entry without one is
|
|
147
|
+
// backfilled to 1 so it serves on a from-0 pull.
|
|
148
|
+
entry.lastMutatedSeq =
|
|
149
|
+
typeof p.lastMutatedSeq === 'number' && Number.isFinite(p.lastMutatedSeq) ? p.lastMutatedSeq : 1;
|
|
145
150
|
return entry;
|
|
146
151
|
});
|
|
152
|
+
// WS2.1 replication bookkeeping (additive). Seed a legacy store with seq=1 +
|
|
153
|
+
// a fresh incarnation: peers hold nothing for a new incarnation, so the
|
|
154
|
+
// first sync is a FULL pull (never a 0-means-unchanged strand). Then, if the
|
|
155
|
+
// meta sidecar's high-water seq EXCEEDS our current seq, the store was
|
|
156
|
+
// rewound (restore) — re-mint the incarnation so peers re-pull wholesale.
|
|
157
|
+
const replicationSeq = typeof store.replicationSeq === 'number' && Number.isFinite(store.replicationSeq) ? store.replicationSeq : 1;
|
|
158
|
+
let storeIncarnation = typeof store.storeIncarnation === 'string' && store.storeIncarnation ? store.storeIncarnation : randomUUID();
|
|
159
|
+
try {
|
|
160
|
+
const metaRaw = fs.readFileSync(`${this.preferencesPath}.meta.json`, 'utf-8');
|
|
161
|
+
const meta = JSON.parse(metaRaw);
|
|
162
|
+
if (typeof meta?.highWaterSeq === 'number' && replicationSeq < meta.highWaterSeq) {
|
|
163
|
+
storeIncarnation = randomUUID();
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
// @silent-fallback-ok — no meta sidecar = no prior advert to rewind below (first boot); nothing to fence
|
|
168
|
+
}
|
|
147
169
|
return {
|
|
148
170
|
schemaVersion: typeof store.schemaVersion === 'number' ? store.schemaVersion : PREFERENCES_SCHEMA_VERSION,
|
|
149
171
|
preferences,
|
|
172
|
+
replicationSeq,
|
|
173
|
+
storeIncarnation,
|
|
150
174
|
};
|
|
151
175
|
}
|
|
152
176
|
/**
|
|
@@ -202,6 +226,18 @@ export class PreferencesManager {
|
|
|
202
226
|
result.violationPattern = violationPattern;
|
|
203
227
|
store.preferences.push(result);
|
|
204
228
|
}
|
|
229
|
+
// WS2.1: every upsert is a state-meaningful mutation — bump the store's
|
|
230
|
+
// monotonic replication seq and stamp it on the upserted entry so the sync
|
|
231
|
+
// delta window catches it. The first write on a FRESH file takes read()'s
|
|
232
|
+
// file-absent early return (no seeded fields), so seed the incarnation here
|
|
233
|
+
// before persisting — otherwise each later read would mint a new one and
|
|
234
|
+
// the advert incarnation would never stabilize.
|
|
235
|
+
if (typeof store.storeIncarnation !== 'string' || !store.storeIncarnation) {
|
|
236
|
+
store.storeIncarnation = randomUUID();
|
|
237
|
+
}
|
|
238
|
+
const nextSeq = (typeof store.replicationSeq === 'number' ? store.replicationSeq : 1) + 1;
|
|
239
|
+
store.replicationSeq = nextSeq;
|
|
240
|
+
result.lastMutatedSeq = nextSeq;
|
|
205
241
|
store.schemaVersion = PREFERENCES_SCHEMA_VERSION;
|
|
206
242
|
this.writeAtomic(store);
|
|
207
243
|
return result;
|
|
@@ -236,6 +272,44 @@ export class PreferencesManager {
|
|
|
236
272
|
fs.closeSync(fd);
|
|
237
273
|
}
|
|
238
274
|
fs.renameSync(tmp, this.preferencesPath);
|
|
275
|
+
// WS2.1 rewind fence: the meta sidecar tracks the high-water replicationSeq.
|
|
276
|
+
// Written AFTER the store rename (a crash between leaves the sidecar BEHIND
|
|
277
|
+
// the store — harmless; ahead would false-trip the rewind fence). The store
|
|
278
|
+
// fd is fsync'd before its rename above, so in program order the sidecar can
|
|
279
|
+
// never be persisted ahead of the store — the fence cannot false-trip on a
|
|
280
|
+
// reorder (review WS2.1 finding #6: ordering verified sufficient, no barrier
|
|
281
|
+
// needed). Best-effort: a sidecar write failure only weakens rewind detection.
|
|
282
|
+
try {
|
|
283
|
+
const seq = store.replicationSeq;
|
|
284
|
+
if (typeof seq === 'number') {
|
|
285
|
+
const metaTmp = `${this.preferencesPath}.meta.json.${process.pid}.tmp`;
|
|
286
|
+
fs.writeFileSync(metaTmp, JSON.stringify({ highWaterSeq: seq }));
|
|
287
|
+
fs.renameSync(metaTmp, `${this.preferencesPath}.meta.json`);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
catch {
|
|
291
|
+
// @silent-fallback-ok — sidecar write failure only weakens rewind detection; the store itself persisted
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* WS2.1 — the replication advert ({ incarnation, replicationSeq }) the
|
|
296
|
+
* `preferences-sync` serve side answers with. Sourced from the on-disk store
|
|
297
|
+
* (read() seeds both fields), so a fresh/legacy store yields a valid advert.
|
|
298
|
+
*/
|
|
299
|
+
getReplicationAdvert() {
|
|
300
|
+
const store = this.read();
|
|
301
|
+
return {
|
|
302
|
+
incarnation: store.storeIncarnation ?? randomUUID(),
|
|
303
|
+
replicationSeq: typeof store.replicationSeq === 'number' ? store.replicationSeq : 1,
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* WS2.1 — the OWN preferences with their replication seqs, for the sync serve
|
|
308
|
+
* side (buildPreferencesSyncPage). Never includes replicas. Each entry's
|
|
309
|
+
* `lastMutatedSeq` is backfilled to 1 by read() when absent.
|
|
310
|
+
*/
|
|
311
|
+
getAllForSync() {
|
|
312
|
+
return this.read().preferences;
|
|
239
313
|
}
|
|
240
314
|
}
|
|
241
315
|
//# sourceMappingURL=PreferencesManager.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PreferencesManager.js","sourceRoot":"","sources":["../../src/core/PreferencesManager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,wEAAwE;AAExE,yEAAyE;AACzE,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"PreferencesManager.js","sourceRoot":"","sources":["../../src/core/PreferencesManager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,wEAAwE;AAExE,yEAAyE;AACzE,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,CAAC;AAuF5C,wEAAwE;AAExE,MAAM,WAAW,GAAqB,EAAE,aAAa,EAAE,0BAA0B,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC;AAErG,SAAS,eAAe,CAAC,KAAyB;IAChD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC;QAAE,OAAO,GAAG,CAAC;IACjE,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,CAAC,CAAC;IACxB,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,CAAC,CAAC;IACxB,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;GAKG;AACH,SAAS,aAAa,CAAC,KAAsB;IAC3C,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAC/C,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACxD,MAAM,UAAU,GAAG,eAAe,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACrD,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC;IACxD,yEAAyE;IACzE,6EAA6E;IAC7E,OAAO,OAAO,GAAG,UAAU,GAAG,WAAW,CAAC;AAC5C,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,gCAAgC,CAC9C,KAAuB,EACvB,QAAQ,GAAG,IAAI;IAEf,MAAM,MAAM,GAAG,CAAC,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1F,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEnC,MAAM,MAAM,GAAG,iDAAiD,CAAC;IACjE,MAAM,KAAK,GAAG,yLAAyL,CAAC;IACxM,MAAM,MAAM,GAAG,4BAA4B,CAAC;IAE5C,gFAAgF;IAChF,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;QAC1B,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,QAAQ,gBAAgB,eAAe,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,WAAW,IAAI,CAAC,CAAC,IAAI,CAAC;QAC7I,MAAM,SAAS,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7E,IAAI,MAAM,CAAC,UAAU,CAAC,SAAS,EAAE,OAAO,CAAC,GAAG,QAAQ;YAAE,MAAM;QAC5D,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvB,CAAC;IAED,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACtC,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,GAAG,SAAS,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC9D,CAAC;AAED,wEAAwE;AAExE,MAAM,OAAO,kBAAkB;IAGT;IAFZ,eAAe,CAAS;IAEhC,YAAoB,QAAgB;QAAhB,aAAQ,GAAR,QAAQ,CAAQ;QAClC,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAAC;IACjE,CAAC;IAED,qEAAqE;IACrE,OAAO;QACL,OAAO,IAAI,CAAC,eAAe,CAAC;IAC9B,CAAC;IAED,+CAA+C;IAC/C,MAAM;QACJ,OAAO,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IAC7C,CAAC;IAED;;;;OAIG;IACH,IAAI;QACF,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;YAAE,OAAO,EAAE,aAAa,EAAE,0BAA0B,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC;QAC1F,IAAI,GAAW,CAAC;QAChB,IAAI,CAAC;YACH,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC;QACvD,CAAC;QAAC,MAAM,CAAC;YACP,qEAAqE;YACrE,OAAO,EAAE,aAAa,EAAE,0BAA0B,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC;QACxE,CAAC;QACD,IAAI,MAAe,CAAC;QACpB,IAAI,CAAC;YACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC3B,CAAC;QAAC,MAAM,CAAC;YACP,oEAAoE;YACpE,OAAO,EAAE,aAAa,EAAE,0BAA0B,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC;QACxE,CAAC;QACD,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAE,MAA2B,CAAC,WAAW,CAAC,EAAE,CAAC;YACtG,OAAO,EAAE,aAAa,EAAE,0BAA0B,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC;QACxE,CAAC;QACD,MAAM,KAAK,GAAG,MAA0B,CAAC;QACzC,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC,MAAM,CAC1C,CAAC,CAAC,EAAwB,EAAE,CAC1B,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,QAAQ,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,SAAS,KAAK,QAAQ,CAC3E,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACV,MAAM,KAAK,GAAoB;gBAC7B,QAAQ,EAAE,CAAC,CAAC,QAAQ;gBACpB,UAAU,EAAE,CAAC,CAAC,CAAC,UAAU,IAAI,iBAAiB,CAAyB;gBACvE,SAAS,EAAE,CAAC,CAAC,SAAS;gBACtB,UAAU,EAAE,OAAO,CAAC,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE;gBACvF,UAAU,EAAE,eAAe,CAAC,CAAC,CAAC,UAAU,CAAC;gBACzC,WAAW,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;aACzD,CAAC;YACF,yEAAyE;YACzE,uEAAuE;YACvE,IAAI,OAAO,CAAC,CAAC,gBAAgB,KAAK,QAAQ,IAAI,CAAC,CAAC,gBAAgB,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACnF,KAAK,CAAC,gBAAgB,GAAG,CAAC,CAAC,gBAAgB,CAAC;YAC9C,CAAC;YACD,qEAAqE;YACrE,iDAAiD;YACjD,KAAK,CAAC,cAAc;gBAClB,OAAO,CAAC,CAAC,cAAc,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;YACnG,OAAO,KAAK,CAAC;QACf,CAAC,CAAC,CAAC;QACH,6EAA6E;QAC7E,wEAAwE;QACxE,6EAA6E;QAC7E,uEAAuE;QACvE,0EAA0E;QAC1E,MAAM,cAAc,GAClB,OAAO,KAAK,CAAC,cAAc,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/G,IAAI,gBAAgB,GAClB,OAAO,KAAK,CAAC,gBAAgB,KAAK,QAAQ,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC;QAC/G,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC,eAAe,YAAY,EAAE,OAAO,CAAC,CAAC;YAC9E,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAA8B,CAAC;YAC9D,IAAI,OAAO,IAAI,EAAE,YAAY,KAAK,QAAQ,IAAI,cAAc,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;gBACjF,gBAAgB,GAAG,UAAU,EAAE,CAAC;YAClC,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,yGAAyG;QAC3G,CAAC;QACD,OAAO;YACL,aAAa,EAAE,OAAO,KAAK,CAAC,aAAa,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,0BAA0B;YACzG,WAAW;YACX,cAAc;YACd,gBAAgB;SACjB,CAAC;IACJ,CAAC;IAED;;;;;;;;;;OAUG;IACH,gBAAgB,CAAC,OAAgC,EAAE,QAAiC,EAAE;QACpF,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC;YACjF,MAAM,IAAI,KAAK,CAAC,yEAAyE,CAAC,CAAC;QAC7F,CAAC;QACD,IAAI,OAAO,OAAO,CAAC,SAAS,KAAK,QAAQ,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC;YACvE,MAAM,IAAI,KAAK,CAAC,0EAA0E,CAAC,CAAC;QAC9F,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC1B,MAAM,GAAG,GAAG,OAAO,CAAC,UAAU,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAC3D,MAAM,UAAU,GAAG,eAAe,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QACvD,MAAM,UAAU,GAAyB,OAAO,CAAC,UAAU,IAAI,iBAAiB,CAAC;QAEjF,4EAA4E;QAC5E,wEAAwE;QACxE,4DAA4D;QAC5D,MAAM,gBAAgB,GACpB,OAAO,OAAO,CAAC,gBAAgB,KAAK,QAAQ,IAAI,OAAO,CAAC,gBAAgB,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;YACxF,CAAC,CAAC,OAAO,CAAC,gBAAgB,CAAC,IAAI,EAAE;YACjC,CAAC,CAAC,SAAS,CAAC;QAEhB,MAAM,QAAQ,GAAG,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;QAClF,IAAI,MAAuB,CAAC;QAC5B,IAAI,QAAQ,EAAE,CAAC;YACb,QAAQ,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;YAC5C,QAAQ,CAAC,UAAU,GAAG,GAAG,CAAC;YAC1B,QAAQ,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC,CAAC;YACjF,QAAQ,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,WAAW,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;YAClE,QAAQ,CAAC,UAAU,GAAG,UAAU,CAAC;YACjC,IAAI,gBAAgB,KAAK,SAAS;gBAAE,QAAQ,CAAC,gBAAgB,GAAG,gBAAgB,CAAC;YACjF,MAAM,GAAG,QAAQ,CAAC;QACpB,CAAC;aAAM,CAAC;YACN,MAAM,GAAG;gBACP,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE;gBACjC,UAAU;gBACV,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,UAAU,EAAE,GAAG;gBACf,UAAU;gBACV,WAAW,EAAE,CAAC;aACf,CAAC;YACF,IAAI,gBAAgB,KAAK,SAAS;gBAAE,MAAM,CAAC,gBAAgB,GAAG,gBAAgB,CAAC;YAC/E,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACjC,CAAC;QAED,wEAAwE;QACxE,2EAA2E;QAC3E,0EAA0E;QAC1E,4EAA4E;QAC5E,yEAAyE;QACzE,gDAAgD;QAChD,IAAI,OAAO,KAAK,CAAC,gBAAgB,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,gBAAgB,EAAE,CAAC;YAC1E,KAAK,CAAC,gBAAgB,GAAG,UAAU,EAAE,CAAC;QACxC,CAAC;QACD,MAAM,OAAO,GAAG,CAAC,OAAO,KAAK,CAAC,cAAc,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAC1F,KAAK,CAAC,cAAc,GAAG,OAAO,CAAC;QAC/B,MAAM,CAAC,cAAc,GAAG,OAAO,CAAC;QAEhC,KAAK,CAAC,aAAa,GAAG,0BAA0B,CAAC;QACjD,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QACxB,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;;;;OAKG;IACH,cAAc,CAAC,QAAQ,GAAG,IAAI;QAK5B,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC1B,MAAM,KAAK,GAAG,gCAAgC,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QAChE,OAAO;YACL,OAAO,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC;YACzB,KAAK;YACL,KAAK,EAAE,KAAK,CAAC,WAAW,CAAC,MAAM;SAChC,CAAC;IACJ,CAAC;IAED,gDAAgD;IACxC,WAAW,CAAC,KAAuB;QACzC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAC/C,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACvC,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,eAAe,QAAQ,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;QACvE,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAC5C,MAAM,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACjC,IAAI,CAAC;YACH,EAAE,CAAC,SAAS,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;YACvB,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QACnB,CAAC;gBAAS,CAAC;YACT,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QACnB,CAAC;QACD,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC;QAEzC,6EAA6E;QAC7E,4EAA4E;QAC5E,4EAA4E;QAC5E,6EAA6E;QAC7E,2EAA2E;QAC3E,6EAA6E;QAC7E,+EAA+E;QAC/E,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,KAAK,CAAC,cAAc,CAAC;YACjC,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;gBAC5B,MAAM,OAAO,GAAG,GAAG,IAAI,CAAC,eAAe,cAAc,OAAO,CAAC,GAAG,MAAM,CAAC;gBACvE,EAAE,CAAC,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;gBACjE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,eAAe,YAAY,CAAC,CAAC;YAC9D,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,wGAAwG;QAC1G,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,oBAAoB;QAClB,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC1B,OAAO;YACL,WAAW,EAAE,KAAK,CAAC,gBAAgB,IAAI,UAAU,EAAE;YACnD,cAAc,EAAE,OAAO,KAAK,CAAC,cAAc,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;SACpF,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACH,aAAa;QACX,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC,WAAW,CAAC;IACjC,CAAC;CACF"}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PreferencesSync — WS2.1 of multi-machine seamlessness: the serve / receive /
|
|
3
|
+
* merge engine behind the `preferences-sync` mesh verb. Replicates the
|
|
4
|
+
* correction-learning preference store (PreferencesManager,
|
|
5
|
+
* `.instar/preferences.json`) across the machine pool so a preference learned on
|
|
6
|
+
* machine A is honored on machine B.
|
|
7
|
+
*
|
|
8
|
+
* Spec: MULTI-MACHINE-SEAMLESSNESS-SPEC §WS2.1. Mirrors the COMMITMENTS-COHERENCE
|
|
9
|
+
* replication pattern (CommitmentsSync.ts) — transport-agnostic, seam-injected;
|
|
10
|
+
* the server registers the serve side as the verb handler and rides the
|
|
11
|
+
* PeerPresencePuller cadence on the receive side, exactly like journal-sync.
|
|
12
|
+
*
|
|
13
|
+
* Preferences are ADVISORY SIGNALS (session-start hints), never authority — so
|
|
14
|
+
* this is read-replication only, no write-back, no election, no quorum.
|
|
15
|
+
*
|
|
16
|
+
* Load-bearing rules (mirrors §3.2):
|
|
17
|
+
* - Pages are seq-windowed DELTAS by `lastMutatedSeq` (asc, dedupeKey tiebreak),
|
|
18
|
+
* EXCLUSIVE cursor, capped at `syncPageBytes` with ≥1 record/page — a store
|
|
19
|
+
* replicates fully over multiple pages, never a blob whose tail strands.
|
|
20
|
+
* - Incarnation fencing: a stale incarnation is answered `incarnationChanged`;
|
|
21
|
+
* the receiver discards the replica wholesale and re-pulls from 0 (a restored
|
|
22
|
+
* `.instar/preferences.json` must never strand replication).
|
|
23
|
+
* - First-hop with teeth: the replica owner derives from the AUTHENTICATED
|
|
24
|
+
* envelope sender; any served row whose originMachineId names a DIFFERENT
|
|
25
|
+
* machine is rejected + counted (forgedRows) — a peer cannot inject rows
|
|
26
|
+
* attributed to a third machine.
|
|
27
|
+
* - Disclosure honesty: the free-text `learning` is credential-shape-scanned at
|
|
28
|
+
* serve time; a flagged row ships with `learning` REDACTED (it still
|
|
29
|
+
* replicates — usefulness never depends on the scan).
|
|
30
|
+
*
|
|
31
|
+
* The ONE merge difference from commitments (design fork, resolved): commitments
|
|
32
|
+
* union on composite key with no cross-origin merge; preferences COLLAPSE by
|
|
33
|
+
* `dedupeKey` because the same dedupeKey on two machines is the SAME learned
|
|
34
|
+
* lesson observed independently. The merged view presents ONE row per dedupeKey
|
|
35
|
+
* (newest `recordedAt` wins the fields; `dedupeCount` sums across origins) so the
|
|
36
|
+
* session-start block never double-injects the same guidance.
|
|
37
|
+
*/
|
|
38
|
+
import type { PreferenceEntry } from './PreferencesManager.js';
|
|
39
|
+
export declare const DEFAULT_SYNC_PAGE_BYTES: number;
|
|
40
|
+
export declare const DEFAULT_REPLICA_STALE_WARN_MS: number;
|
|
41
|
+
/** Per-store bound — preferences are few; a runaway peer can't bloat the merge. */
|
|
42
|
+
export declare const DEFAULT_MAX_REPLICATED_PREFERENCES = 500;
|
|
43
|
+
export interface PreferencesSyncRequest {
|
|
44
|
+
sinceSeq: number;
|
|
45
|
+
incarnation?: string;
|
|
46
|
+
}
|
|
47
|
+
/** A preference as it travels: always origin-stamped + seq-stamped, possibly redacted. */
|
|
48
|
+
export interface ReplicatedPreference extends PreferenceEntry {
|
|
49
|
+
originMachineId: string;
|
|
50
|
+
/** Monotonic per-origin mutation sequence — the delta-window key. */
|
|
51
|
+
lastMutatedSeq: number;
|
|
52
|
+
/** True when `learning` was credential-redacted at serve time. */
|
|
53
|
+
textRedacted?: boolean;
|
|
54
|
+
}
|
|
55
|
+
export interface PreferencesSyncPage {
|
|
56
|
+
incarnation: string;
|
|
57
|
+
replicationSeq: number;
|
|
58
|
+
/** Served records (redacted + origin-stamped). Empty when caught up. */
|
|
59
|
+
records: ReplicatedPreference[];
|
|
60
|
+
/** EXCLUSIVE cursor for the next request. */
|
|
61
|
+
nextSinceSeq: number;
|
|
62
|
+
/** True when no records remain past nextSinceSeq. */
|
|
63
|
+
done: boolean;
|
|
64
|
+
/** Set when the requester's incarnation is stale — re-pull from 0. */
|
|
65
|
+
incarnationChanged?: boolean;
|
|
66
|
+
}
|
|
67
|
+
/** A preference plus its (possibly absent → 0) replication seq, from the own store. */
|
|
68
|
+
export interface ServeablePreference extends PreferenceEntry {
|
|
69
|
+
/** Absent on a legacy store ⇒ treated as 0 so a first sync replicates fully. */
|
|
70
|
+
lastMutatedSeq?: number;
|
|
71
|
+
}
|
|
72
|
+
export interface ServePageDeps {
|
|
73
|
+
ownMachineId: string;
|
|
74
|
+
/** The OWN store's preferences — never replicas. */
|
|
75
|
+
records: ServeablePreference[];
|
|
76
|
+
advert: {
|
|
77
|
+
incarnation: string;
|
|
78
|
+
replicationSeq: number;
|
|
79
|
+
};
|
|
80
|
+
syncPageBytes?: number;
|
|
81
|
+
}
|
|
82
|
+
export declare function buildPreferencesSyncPage(req: PreferencesSyncRequest, deps: ServePageDeps): PreferencesSyncPage;
|
|
83
|
+
export interface ApplyResult {
|
|
84
|
+
applied: number;
|
|
85
|
+
/** Rows claiming an originMachineId ≠ the authenticated sender — rejected. */
|
|
86
|
+
forgedRows: number;
|
|
87
|
+
/** The replica was discarded wholesale (incarnation change). */
|
|
88
|
+
replaced: boolean;
|
|
89
|
+
/** Rows dropped because the per-peer bound was already reached. */
|
|
90
|
+
dropped: number;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* The per-peer replica store: one JSON file per owner under
|
|
94
|
+
* `state/preference-replicas/`, written ONLY by this receive path
|
|
95
|
+
* (single-writer), temp-file + atomic rename, corrupt → quarantine + fresh
|
|
96
|
+
* (never silently empty).
|
|
97
|
+
*/
|
|
98
|
+
export declare class PreferenceReplicaStore {
|
|
99
|
+
private readonly dir;
|
|
100
|
+
private readonly now;
|
|
101
|
+
private readonly logger;
|
|
102
|
+
private readonly maxRecords;
|
|
103
|
+
private cache;
|
|
104
|
+
constructor(config: {
|
|
105
|
+
stateDir: string;
|
|
106
|
+
now?: () => Date;
|
|
107
|
+
logger?: (msg: string) => void;
|
|
108
|
+
maxRecordsPerPeer?: number;
|
|
109
|
+
});
|
|
110
|
+
/** The cursor to request next from a peer (0 + no incarnation when fresh). */
|
|
111
|
+
cursorFor(ownerMachineId: string): {
|
|
112
|
+
sinceSeq: number;
|
|
113
|
+
incarnation?: string;
|
|
114
|
+
};
|
|
115
|
+
/**
|
|
116
|
+
* Apply a served page. `senderMachineId` is the AUTHENTICATED envelope
|
|
117
|
+
* sender — the replica identity derives from it, never a payload field.
|
|
118
|
+
*/
|
|
119
|
+
applyPage(senderMachineId: string, page: PreferencesSyncPage): ApplyResult;
|
|
120
|
+
/** Every replica's rows, tagged with owner + receivedAt. */
|
|
121
|
+
allReplicas(): {
|
|
122
|
+
ownerMachineId: string;
|
|
123
|
+
receivedAt: string;
|
|
124
|
+
records: ReplicatedPreference[];
|
|
125
|
+
}[];
|
|
126
|
+
private fileFor;
|
|
127
|
+
private load;
|
|
128
|
+
private persist;
|
|
129
|
+
}
|
|
130
|
+
export interface MergedPreference extends PreferenceEntry {
|
|
131
|
+
/** Every machine that has observed this dedupeKey (own included). */
|
|
132
|
+
contributingMachines: string[];
|
|
133
|
+
/** Newest contributor — whose fields won. */
|
|
134
|
+
winningMachineId: string;
|
|
135
|
+
/** True when ≥1 contributing row was credential-redacted. */
|
|
136
|
+
textRedacted?: boolean;
|
|
137
|
+
}
|
|
138
|
+
export interface MergeDeps {
|
|
139
|
+
ownMachineId: string;
|
|
140
|
+
own: PreferenceEntry[];
|
|
141
|
+
replicas: {
|
|
142
|
+
ownerMachineId: string;
|
|
143
|
+
receivedAt: string;
|
|
144
|
+
records: ReplicatedPreference[];
|
|
145
|
+
}[];
|
|
146
|
+
/** Injectable clock for the skew cap (default `new Date()`). Tests pass a fixed now. */
|
|
147
|
+
now?: () => Date;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Clock-skew tolerance for merge ordering. A peer's `recordedAt` is capped at
|
|
151
|
+
* `now + this` before it can win a dedupeKey collision — so a machine with a
|
|
152
|
+
* fast/hostile clock (e.g. set a year ahead) cannot silently dominate EVERY
|
|
153
|
+
* preference across the pool (review WS2.1 finding #2; the spec's clock-skew
|
|
154
|
+
* requirement). Real-world cross-machine clock drift is seconds-to-minutes; a
|
|
155
|
+
* full day is a generous ceiling that never penalizes honest machines.
|
|
156
|
+
* NOTE: this is the shipped mitigation; full HLC (logical counters) is a tracked
|
|
157
|
+
* follow-up. <!-- tracked: WS2.1 HLC counters -->
|
|
158
|
+
*/
|
|
159
|
+
export declare const CLOCK_SKEW_TOLERANCE_MS: number;
|
|
160
|
+
/**
|
|
161
|
+
* Collapse own + replicas by dedupeKey into one merged row per learned
|
|
162
|
+
* preference. Newest (recordedAt, origin) wins the fields; dedupeCount SUMS
|
|
163
|
+
* across the distinct contributing origins (true cross-machine observation
|
|
164
|
+
* count); contributingMachines lists every origin that holds the key.
|
|
165
|
+
*/
|
|
166
|
+
export declare function mergePreferenceViews(deps: MergeDeps): MergedPreference[];
|
|
167
|
+
//# sourceMappingURL=PreferencesSync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PreferencesSync.d.ts","sourceRoot":"","sources":["../../src/core/PreferencesSync.ts"],"names":[],"mappings":"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"}
|