instar 1.3.339 → 1.3.340
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 +166 -10
- package/dist/commands/server.js.map +1 -1
- package/dist/config/ConfigDefaults.d.ts.map +1 -1
- package/dist/config/ConfigDefaults.js +17 -0
- package/dist/config/ConfigDefaults.js.map +1 -1
- package/dist/core/AutonomousSessions.d.ts +17 -2
- package/dist/core/AutonomousSessions.d.ts.map +1 -1
- package/dist/core/AutonomousSessions.js +30 -4
- package/dist/core/AutonomousSessions.js.map +1 -1
- package/dist/core/CoherenceJournal.d.ts +326 -0
- package/dist/core/CoherenceJournal.d.ts.map +1 -0
- package/dist/core/CoherenceJournal.js +999 -0
- package/dist/core/CoherenceJournal.js.map +1 -0
- package/dist/core/CoherenceJournalReader.d.ts +158 -0
- package/dist/core/CoherenceJournalReader.d.ts.map +1 -0
- package/dist/core/CoherenceJournalReader.js +450 -0
- package/dist/core/CoherenceJournalReader.js.map +1 -0
- package/dist/core/JournalSyncApplier.d.ts +272 -0
- package/dist/core/JournalSyncApplier.d.ts.map +1 -0
- package/dist/core/JournalSyncApplier.js +835 -0
- package/dist/core/JournalSyncApplier.js.map +1 -0
- package/dist/core/StateManager.d.ts +41 -0
- package/dist/core/StateManager.d.ts.map +1 -1
- package/dist/core/StateManager.js +100 -0
- package/dist/core/StateManager.js.map +1 -1
- package/dist/core/types.d.ts +35 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/messaging/TelegramAdapter.d.ts +14 -0
- package/dist/messaging/TelegramAdapter.d.ts.map +1 -1
- package/dist/messaging/TelegramAdapter.js +16 -1
- package/dist/messaging/TelegramAdapter.js.map +1 -1
- package/dist/scaffold/templates.d.ts.map +1 -1
- package/dist/scaffold/templates.js +7 -0
- package/dist/scaffold/templates.js.map +1 -1
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +54 -3
- package/dist/server/routes.js.map +1 -1
- package/package.json +2 -2
- package/scripts/lint-cas-emit-placement.js +87 -0
- package/scripts/lint-journal-actuation-ban.js +63 -0
- package/scripts/lint-state-registry.js +313 -0
- package/src/data/builtin-manifest.json +46 -46
- package/src/data/state-coherence-registry.json +880 -0
- package/src/scaffold/templates.ts +7 -0
- package/upgrades/1.3.340.md +132 -0
- package/upgrades/coherence-journal-p1-1.eli16.md +11 -0
- package/upgrades/coherence-journal-p1-2.eli16.md +11 -0
- package/upgrades/coherence-journal-p1-3.eli16.md +13 -0
- package/upgrades/side-effects/coherence-journal-p1-1.md +68 -0
- package/upgrades/side-effects/coherence-journal-p1-2.md +54 -0
- package/upgrades/side-effects/coherence-journal-p1-3.md +49 -0
- package/upgrades/1.3.339.md +0 -48
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CoherenceJournalReader — the bounded, merged READ path for the coherence
|
|
3
|
+
* journal (P1.2 of multi-machine coherence).
|
|
4
|
+
*
|
|
5
|
+
* Spec: docs/specs/COHERENCE-JOURNAL-SPEC.md §3.5 (Read API — bounded, honest
|
|
6
|
+
* about trust and time) and §3.1 (stream layout).
|
|
7
|
+
*
|
|
8
|
+
* DELIBERATELY SEPARATE from the writer (`CoherenceJournal`): §3.9's
|
|
9
|
+
* actuation-ban lint targets imports of THIS module — no actuating code path
|
|
10
|
+
* (kill / spawn / place / transfer / reap) may consume journal data. Keeping
|
|
11
|
+
* the reader its own module gives that lint a single, precise symbol to grep.
|
|
12
|
+
*
|
|
13
|
+
* Read-side discipline (§3.5):
|
|
14
|
+
* - `machine` / `kind` query params are NEVER used to build a file path. They
|
|
15
|
+
* are matched against the enumerated on-disk stream set (a directory
|
|
16
|
+
* listing), so a traversal-shaped param simply matches nothing — the
|
|
17
|
+
* read-side mirror of the write-side sanitization.
|
|
18
|
+
* - Reads are reverse-tail (reuse `readTailTolerant`), O(limit) not O(file).
|
|
19
|
+
* - `limit` is server-capped (≤500). Each query has a total byte ceiling
|
|
20
|
+
* (default 4MB) and a generic per-stream archive-file scan cap (default 8)
|
|
21
|
+
* — EXCEPT `kind=topic-placement` queries, which are ANSWER-COMPLETE: they
|
|
22
|
+
* scan all placement archives newest-first until `limit` is satisfied (the
|
|
23
|
+
* byte ceiling stays the hard bound). Over any bound → partial +
|
|
24
|
+
* `truncated: true`.
|
|
25
|
+
* - Merged ordering: `(epoch, ts)` for topic-placement (epoch from
|
|
26
|
+
* `data.epoch`); `(ts, machineId, seq)` for other kinds. The opaque
|
|
27
|
+
* base64url cursor encodes THE QUERY'S order key — a cursor over a different
|
|
28
|
+
* key than the sort order would skip/duplicate at boundaries. A malformed
|
|
29
|
+
* cursor is rejected with a clean error, never a crash.
|
|
30
|
+
* - topic-placement entries sharing one `(topic, epoch)` collapse to
|
|
31
|
+
* first-seen (defense-in-depth dedupe, §3.1).
|
|
32
|
+
* - Per-line tolerant parsing everywhere; corrupt lines skipped + counted.
|
|
33
|
+
* - Replication states (`behind`/`gapped`/`suspect`/`reset`) arrive in P1.3;
|
|
34
|
+
* P1.2 reports status `current` for every present stream.
|
|
35
|
+
*/
|
|
36
|
+
import fs from 'node:fs';
|
|
37
|
+
import path from 'node:path';
|
|
38
|
+
import { JOURNAL_KINDS, readTailTolerant, } from './CoherenceJournal.js';
|
|
39
|
+
/** Server-side caps (§3.5). */
|
|
40
|
+
export const READER_MAX_LIMIT = 500;
|
|
41
|
+
export const READER_DEFAULT_LIMIT = 100;
|
|
42
|
+
/** Per-query total byte ceiling — the hard bound across ALL streams scanned. */
|
|
43
|
+
export const READER_DEFAULT_BYTE_CEILING = 4 * 1024 * 1024;
|
|
44
|
+
/** Generic archive-file scan cap per stream (NOT applied to topic-placement). */
|
|
45
|
+
export const READER_DEFAULT_ARCHIVE_CAP = 8;
|
|
46
|
+
/** Raised when a supplied cursor cannot be parsed. The route maps it to 400. */
|
|
47
|
+
export class InvalidCursorError extends Error {
|
|
48
|
+
constructor(message = 'invalid cursor') {
|
|
49
|
+
super(message);
|
|
50
|
+
this.name = 'InvalidCursorError';
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function realFs() {
|
|
54
|
+
return {
|
|
55
|
+
openSync: fs.openSync,
|
|
56
|
+
writeSync: fs.writeSync,
|
|
57
|
+
fdatasyncSync: fs.fdatasyncSync,
|
|
58
|
+
closeSync: fs.closeSync,
|
|
59
|
+
existsSync: fs.existsSync,
|
|
60
|
+
statSync: fs.statSync,
|
|
61
|
+
renameSync: fs.renameSync,
|
|
62
|
+
writeFileSync: fs.writeFileSync,
|
|
63
|
+
readFileSync: fs.readFileSync,
|
|
64
|
+
readdirSync: fs.readdirSync,
|
|
65
|
+
truncateSync: fs.truncateSync,
|
|
66
|
+
mkdirSync: fs.mkdirSync,
|
|
67
|
+
readSync: fs.readSync,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
function escapeRegExp(s) {
|
|
71
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
72
|
+
}
|
|
73
|
+
// RULE 3: EXEMPT — this is NOT a provider/CLI state-detector (the Rule-3 class:
|
|
74
|
+
// is_running / pane-state / prompt-readiness detection across agent frameworks).
|
|
75
|
+
// It reads the coherence journal's own append-only JSONL streams and returns a
|
|
76
|
+
// merged history view; there is no external process/provider state being sniffed,
|
|
77
|
+
// no fallback chain to mis-detect. Tolerant line-parsing + skippedCorrupt is its
|
|
78
|
+
// robustness surface (COHERENCE-JOURNAL-SPEC §3.5), not provider-portability.
|
|
79
|
+
export class CoherenceJournalReader {
|
|
80
|
+
stateDir;
|
|
81
|
+
byteCeiling;
|
|
82
|
+
archiveCap;
|
|
83
|
+
now;
|
|
84
|
+
io;
|
|
85
|
+
constructor(config) {
|
|
86
|
+
this.stateDir = config.stateDir;
|
|
87
|
+
this.byteCeiling = config.byteCeiling ?? READER_DEFAULT_BYTE_CEILING;
|
|
88
|
+
this.archiveCap = config.archiveCap ?? READER_DEFAULT_ARCHIVE_CAP;
|
|
89
|
+
this.now = config.now ?? (() => new Date());
|
|
90
|
+
this.io = config.fsImpl ?? realFs();
|
|
91
|
+
}
|
|
92
|
+
// ---- paths --------------------------------------------------------------
|
|
93
|
+
dirPath() {
|
|
94
|
+
return path.join(this.stateDir, 'state', 'coherence-journal');
|
|
95
|
+
}
|
|
96
|
+
peersDirPath() {
|
|
97
|
+
return path.join(this.dirPath(), 'peers');
|
|
98
|
+
}
|
|
99
|
+
// ---- stream enumeration (the ONLY way machine/kind params are honored) ---
|
|
100
|
+
/**
|
|
101
|
+
* Enumerate every on-disk stream file (own current + archives, peer replicas).
|
|
102
|
+
* `machine` / `kind` filters are matched HERE against the discovered set —
|
|
103
|
+
* never used to build a path — so a traversal-shaped param matches nothing.
|
|
104
|
+
*/
|
|
105
|
+
enumerate(filterMachine, filterKind) {
|
|
106
|
+
const out = [];
|
|
107
|
+
// Own + peer directories use the SAME filename grammar:
|
|
108
|
+
// <machineId>.<kind>.jsonl (current)
|
|
109
|
+
// <machineId>.<kind>.<digits>.jsonl (archive)
|
|
110
|
+
// The machineId is whatever literal precedes `.<kind>.` on disk (already
|
|
111
|
+
// sanitized at write time). We compare the matched literal against the
|
|
112
|
+
// filter rather than constructing a path from it.
|
|
113
|
+
this.scanDir(this.dirPath(), 'own', out);
|
|
114
|
+
this.scanDir(this.peersDirPath(), 'replica', out);
|
|
115
|
+
return out.filter((s) => {
|
|
116
|
+
if (filterKind !== undefined && s.kind !== filterKind)
|
|
117
|
+
return false;
|
|
118
|
+
if (filterMachine !== undefined && s.machineId !== filterMachine)
|
|
119
|
+
return false;
|
|
120
|
+
return true;
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
scanDir(dir, source, out) {
|
|
124
|
+
let names;
|
|
125
|
+
try {
|
|
126
|
+
names = this.io.readdirSync(dir);
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
return; // dir absent (e.g. no peers yet) → no streams from here
|
|
130
|
+
}
|
|
131
|
+
// For each known kind, match `<machineId>.<kind>.jsonl` and
|
|
132
|
+
// `<machineId>.<kind>.<digits>.jsonl`. machineId is `[^/]+?` but in
|
|
133
|
+
// practice the write-time sanitization keeps it to [A-Za-z0-9_%-].
|
|
134
|
+
for (const kind of JOURNAL_KINDS) {
|
|
135
|
+
const k = escapeRegExp(kind);
|
|
136
|
+
const re = new RegExp(`^(.+)\\.${k}(?:\\.(\\d+))?\\.jsonl$`);
|
|
137
|
+
for (const name of names) {
|
|
138
|
+
const m = re.exec(name);
|
|
139
|
+
if (!m)
|
|
140
|
+
continue;
|
|
141
|
+
const machineId = m[1];
|
|
142
|
+
const isArchive = m[2] !== undefined;
|
|
143
|
+
out.push({
|
|
144
|
+
machineId,
|
|
145
|
+
kind,
|
|
146
|
+
file: path.join(dir, name),
|
|
147
|
+
isArchive,
|
|
148
|
+
source,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// ---- cursor (opaque base64url keyset) -----------------------------------
|
|
154
|
+
encodeCursor(c) {
|
|
155
|
+
return Buffer.from(JSON.stringify(c), 'utf-8').toString('base64url');
|
|
156
|
+
}
|
|
157
|
+
decodeCursor(raw, isPlacement) {
|
|
158
|
+
let obj;
|
|
159
|
+
try {
|
|
160
|
+
const json = Buffer.from(raw, 'base64url').toString('utf-8');
|
|
161
|
+
obj = JSON.parse(json);
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
throw new InvalidCursorError();
|
|
165
|
+
}
|
|
166
|
+
if (!obj || typeof obj !== 'object')
|
|
167
|
+
throw new InvalidCursorError();
|
|
168
|
+
const o = obj;
|
|
169
|
+
if (typeof o.ts !== 'string' || typeof o.machineId !== 'string' || typeof o.seq !== 'number') {
|
|
170
|
+
throw new InvalidCursorError();
|
|
171
|
+
}
|
|
172
|
+
if (isPlacement) {
|
|
173
|
+
if (typeof o.epoch !== 'number' || !Number.isFinite(o.epoch)) {
|
|
174
|
+
throw new InvalidCursorError('cursor key does not match query order');
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
...(isPlacement ? { epoch: o.epoch } : {}),
|
|
179
|
+
ts: o.ts,
|
|
180
|
+
machineId: o.machineId,
|
|
181
|
+
seq: o.seq,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
// ---- the main query -----------------------------------------------------
|
|
185
|
+
query(opts = {}) {
|
|
186
|
+
const limit = this.clampLimit(opts.limit);
|
|
187
|
+
const kindFilter = opts.kind;
|
|
188
|
+
const machineFilter = opts.machine;
|
|
189
|
+
const topicFilter = typeof opts.topic === 'number' ? opts.topic : undefined;
|
|
190
|
+
const isPlacement = kindFilter === 'topic-placement';
|
|
191
|
+
const streams = this.enumerate(machineFilter, kindFilter);
|
|
192
|
+
// A cursor only round-trips against the query's order key. If a cursor is
|
|
193
|
+
// present we decode it (rejecting a mismatched/garbled one) before reading.
|
|
194
|
+
const cursor = opts.cursor ? this.decodeCursor(opts.cursor, isPlacement) : undefined;
|
|
195
|
+
// Read entries from every matched stream, newest-first, under the shared
|
|
196
|
+
// byte ceiling. The placement exemption (answer-complete) is applied per
|
|
197
|
+
// stream while accumulating.
|
|
198
|
+
const collected = [];
|
|
199
|
+
let skippedCorrupt = 0;
|
|
200
|
+
let truncated = false;
|
|
201
|
+
let bytesRemaining = this.byteCeiling;
|
|
202
|
+
// Group discovered files by (source, machineId, kind) so we can scan a
|
|
203
|
+
// stream's current file + its archives newest-first as one logical stream.
|
|
204
|
+
const grouped = this.groupStreams(streams);
|
|
205
|
+
for (const group of grouped) {
|
|
206
|
+
// current first (newest), then archives newest→oldest.
|
|
207
|
+
const ordered = this.orderNewestFirst(group.files);
|
|
208
|
+
const isPlacementStream = group.kind === 'topic-placement';
|
|
209
|
+
let archivesScanned = 0;
|
|
210
|
+
for (const f of ordered) {
|
|
211
|
+
if (bytesRemaining <= 0) {
|
|
212
|
+
truncated = true;
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
// Generic archive scan cap — NOT applied to topic-placement (§3.5
|
|
216
|
+
// answer-complete). The current file is always read; the cap counts
|
|
217
|
+
// archive files only.
|
|
218
|
+
if (f.isArchive && !isPlacementStream && archivesScanned >= this.archiveCap) {
|
|
219
|
+
truncated = true;
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
if (f.isArchive)
|
|
223
|
+
archivesScanned++;
|
|
224
|
+
// Read this file under the *remaining* byte budget. readTailTolerant
|
|
225
|
+
// reads at most `bytesRemaining` bytes from the file end and reports
|
|
226
|
+
// truncation if it could not read the whole file.
|
|
227
|
+
const read = readTailTolerant(this.io, f.file, READER_MAX_LIMIT, bytesRemaining);
|
|
228
|
+
skippedCorrupt += read.skippedCorrupt;
|
|
229
|
+
if (read.truncated)
|
|
230
|
+
truncated = true;
|
|
231
|
+
// Subtract what readTailTolerant actually consumed (file size bounded
|
|
232
|
+
// by the remaining budget) so the ceiling is shared across all streams.
|
|
233
|
+
const fileSize = this.safeSize(f.file);
|
|
234
|
+
bytesRemaining -= Math.min(fileSize, bytesRemaining);
|
|
235
|
+
for (const e of read.entries) {
|
|
236
|
+
if (topicFilter !== undefined && e.topic !== topicFilter)
|
|
237
|
+
continue;
|
|
238
|
+
collected.push({
|
|
239
|
+
...e,
|
|
240
|
+
source: group.source,
|
|
241
|
+
...(group.source === 'replica' ? { recvTs: this.recvTsFor(f.file) } : {}),
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
// Defense-in-depth (topic,epoch) collapse for placement.
|
|
247
|
+
const deduped = isPlacement ? this.collapsePlacement(collected) : collected;
|
|
248
|
+
// Merge-order across all streams.
|
|
249
|
+
const sorted = this.sortMerged(deduped, isPlacement);
|
|
250
|
+
// Apply the cursor (keyset: strictly AFTER the cursor in sort order).
|
|
251
|
+
const afterCursor = cursor ? this.dropThroughCursor(sorted, cursor, isPlacement) : sorted;
|
|
252
|
+
// Page.
|
|
253
|
+
const page = afterCursor.slice(0, limit);
|
|
254
|
+
if (afterCursor.length > limit) {
|
|
255
|
+
// There's a next page; truncation here is paging, not a bound hit, so we
|
|
256
|
+
// do NOT set truncated for it — `truncated` is reserved for byte/archive
|
|
257
|
+
// bound hits per §3.5. (A consumer pages via the next cursor.)
|
|
258
|
+
}
|
|
259
|
+
return {
|
|
260
|
+
entries: page,
|
|
261
|
+
streams: this.buildStreamMap(streams),
|
|
262
|
+
skippedCorrupt,
|
|
263
|
+
truncated,
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
/** The opaque cursor for the LAST entry of a page (callers echo it back). */
|
|
267
|
+
cursorFor(entry, isPlacement) {
|
|
268
|
+
const c = {
|
|
269
|
+
...(isPlacement ? { epoch: this.epochOf(entry) } : {}),
|
|
270
|
+
ts: entry.ts,
|
|
271
|
+
machineId: entry.machine,
|
|
272
|
+
seq: entry.seq,
|
|
273
|
+
};
|
|
274
|
+
return this.encodeCursor(c);
|
|
275
|
+
}
|
|
276
|
+
// ---- ordering + dedupe --------------------------------------------------
|
|
277
|
+
epochOf(e) {
|
|
278
|
+
const ep = e.data?.epoch;
|
|
279
|
+
return typeof ep === 'number' && Number.isFinite(ep) ? ep : 0;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Merge order (§3.5):
|
|
283
|
+
* - topic-placement: (epoch, ts, machineId, seq)
|
|
284
|
+
* - other kinds: (ts, machineId, seq)
|
|
285
|
+
* Returned NEWEST-FIRST (descending) — the read API returns most-recent.
|
|
286
|
+
*/
|
|
287
|
+
sortMerged(entries, isPlacement) {
|
|
288
|
+
const copy = entries.slice();
|
|
289
|
+
copy.sort((a, b) => -this.compareKey(a, b, isPlacement)); // negate → descending
|
|
290
|
+
return copy;
|
|
291
|
+
}
|
|
292
|
+
/** Ascending compare on the query's order key. */
|
|
293
|
+
compareKey(a, b, isPlacement) {
|
|
294
|
+
if (isPlacement) {
|
|
295
|
+
const ea = this.epochOf(a);
|
|
296
|
+
const eb = this.epochOf(b);
|
|
297
|
+
if (ea !== eb)
|
|
298
|
+
return ea - eb;
|
|
299
|
+
}
|
|
300
|
+
if (a.ts !== b.ts)
|
|
301
|
+
return a.ts < b.ts ? -1 : 1;
|
|
302
|
+
if (a.machine !== b.machine)
|
|
303
|
+
return a.machine < b.machine ? -1 : 1;
|
|
304
|
+
return a.seq - b.seq;
|
|
305
|
+
}
|
|
306
|
+
/** Compare an entry against a cursor on the query's order key (ascending). */
|
|
307
|
+
compareToCursor(e, c, isPlacement) {
|
|
308
|
+
if (isPlacement) {
|
|
309
|
+
const ee = this.epochOf(e);
|
|
310
|
+
const ce = c.epoch ?? 0;
|
|
311
|
+
if (ee !== ce)
|
|
312
|
+
return ee - ce;
|
|
313
|
+
}
|
|
314
|
+
if (e.ts !== c.ts)
|
|
315
|
+
return e.ts < c.ts ? -1 : 1;
|
|
316
|
+
if (e.machine !== c.machineId)
|
|
317
|
+
return e.machine < c.machineId ? -1 : 1;
|
|
318
|
+
return e.seq - c.seq;
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Keyset pagination: results are NEWEST-FIRST, the cursor names the last
|
|
322
|
+
* entry already returned, so the next page is everything STRICTLY BEFORE
|
|
323
|
+
* the cursor in descending order (i.e. compareToCursor < 0). No skip/dup at
|
|
324
|
+
* equal-ts boundaries because the full composite key disambiguates.
|
|
325
|
+
*/
|
|
326
|
+
dropThroughCursor(sorted, c, isPlacement) {
|
|
327
|
+
return sorted.filter((e) => this.compareToCursor(e, c, isPlacement) < 0);
|
|
328
|
+
}
|
|
329
|
+
/** topic-placement (topic, epoch) collapse to first-seen (§3.1 dedupe). */
|
|
330
|
+
collapsePlacement(entries) {
|
|
331
|
+
const seen = new Set();
|
|
332
|
+
const out = [];
|
|
333
|
+
for (const e of entries) {
|
|
334
|
+
const key = `${e.topic}:${this.epochOf(e)}`;
|
|
335
|
+
if (seen.has(key))
|
|
336
|
+
continue;
|
|
337
|
+
seen.add(key);
|
|
338
|
+
out.push(e);
|
|
339
|
+
}
|
|
340
|
+
return out;
|
|
341
|
+
}
|
|
342
|
+
// ---- stream grouping + file ordering ------------------------------------
|
|
343
|
+
groupStreams(streams) {
|
|
344
|
+
const map = new Map();
|
|
345
|
+
for (const s of streams) {
|
|
346
|
+
const key = `${s.source}|${s.machineId}|${s.kind}`;
|
|
347
|
+
let g = map.get(key);
|
|
348
|
+
if (!g) {
|
|
349
|
+
g = { source: s.source, machineId: s.machineId, kind: s.kind, files: [] };
|
|
350
|
+
map.set(key, g);
|
|
351
|
+
}
|
|
352
|
+
g.files.push(s);
|
|
353
|
+
}
|
|
354
|
+
return [...map.values()];
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Newest-first file order for one stream: the current file (no numeric
|
|
358
|
+
* stamp) first, then archives by descending numeric stamp (newest archive
|
|
359
|
+
* before oldest). Archive stamps embed the rotation time (see writer).
|
|
360
|
+
*/
|
|
361
|
+
orderNewestFirst(files) {
|
|
362
|
+
const current = files.filter((f) => !f.isArchive);
|
|
363
|
+
const archives = files.filter((f) => f.isArchive);
|
|
364
|
+
archives.sort((a, b) => this.archiveStamp(b.file) - this.archiveStamp(a.file)); // newest first
|
|
365
|
+
return [...current, ...archives];
|
|
366
|
+
}
|
|
367
|
+
archiveStamp(file) {
|
|
368
|
+
const m = /\.(\d+)\.jsonl$/.exec(path.basename(file));
|
|
369
|
+
return m ? Number(m[1]) : 0;
|
|
370
|
+
}
|
|
371
|
+
// ---- streams map (status + staleness) -----------------------------------
|
|
372
|
+
/**
|
|
373
|
+
* Build the response `streams` map: one row per discovered stream file's
|
|
374
|
+
* logical stream (`<machineId>.<kind>`), reading the durable tail for
|
|
375
|
+
* lastSeq / lastTs and meta for incarnation. P1.2 reports status `current`.
|
|
376
|
+
*/
|
|
377
|
+
buildStreamMap(streams) {
|
|
378
|
+
const out = {};
|
|
379
|
+
const groups = this.groupStreams(streams);
|
|
380
|
+
const nowMs = this.now().getTime();
|
|
381
|
+
for (const g of groups) {
|
|
382
|
+
const key = `${g.machineId}.${g.kind}`;
|
|
383
|
+
// Read the most-recent entry from the newest file for lastSeq/lastTs.
|
|
384
|
+
const ordered = this.orderNewestFirst(g.files);
|
|
385
|
+
let lastSeq = 0;
|
|
386
|
+
let lastTs = null;
|
|
387
|
+
for (const f of ordered) {
|
|
388
|
+
const read = readTailTolerant(this.io, f.file, 1, this.byteCeiling);
|
|
389
|
+
if (read.entries.length > 0) {
|
|
390
|
+
lastSeq = read.entries[0].seq;
|
|
391
|
+
lastTs = read.entries[0].ts;
|
|
392
|
+
break;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
const incarnation = this.readIncarnation(g.source, g.machineId);
|
|
396
|
+
out[key] = {
|
|
397
|
+
...(incarnation ? { incarnation } : {}),
|
|
398
|
+
lastSeq,
|
|
399
|
+
lastTs,
|
|
400
|
+
source: g.source,
|
|
401
|
+
status: 'current', // P1.2: replication states land in P1.3
|
|
402
|
+
stalenessMs: lastTs ? Math.max(0, nowMs - new Date(lastTs).getTime()) : null,
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
return out;
|
|
406
|
+
}
|
|
407
|
+
/** Read the incarnation token from the stream set's meta sidecar, if present. */
|
|
408
|
+
readIncarnation(source, machineId) {
|
|
409
|
+
const dir = source === 'own' ? this.dirPath() : this.peersDirPath();
|
|
410
|
+
const metaPath = path.join(dir, `${machineId}.meta.json`);
|
|
411
|
+
try {
|
|
412
|
+
if (!this.io.existsSync(metaPath))
|
|
413
|
+
return undefined;
|
|
414
|
+
const raw = this.io.readFileSync(metaPath, 'utf-8');
|
|
415
|
+
const obj = JSON.parse(raw);
|
|
416
|
+
return typeof obj?.incarnation === 'string' ? obj.incarnation : undefined;
|
|
417
|
+
}
|
|
418
|
+
catch { /* @silent-fallback-ok: journal observability must never endanger the observed operation (COHERENCE-JOURNAL-SPEC §3.1) */
|
|
419
|
+
return undefined;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* recvTs for a replica file. P1.2 has no per-entry receipt stamp on disk yet
|
|
424
|
+
* (that rides the P1.3 apply path); we surface the replica file's mtime as a
|
|
425
|
+
* best-effort "when this machine last learned something on this stream".
|
|
426
|
+
*/
|
|
427
|
+
recvTsFor(file) {
|
|
428
|
+
try {
|
|
429
|
+
const st = this.io.statSync(file);
|
|
430
|
+
return new Date(st.mtimeMs).toISOString();
|
|
431
|
+
}
|
|
432
|
+
catch { /* @silent-fallback-ok: journal observability must never endanger the observed operation (COHERENCE-JOURNAL-SPEC §3.1) */
|
|
433
|
+
return undefined;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
safeSize(file) {
|
|
437
|
+
try {
|
|
438
|
+
return this.io.statSync(file).size;
|
|
439
|
+
}
|
|
440
|
+
catch { /* @silent-fallback-ok: journal observability must never endanger the observed operation (COHERENCE-JOURNAL-SPEC §3.1) */
|
|
441
|
+
return 0;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
clampLimit(raw) {
|
|
445
|
+
if (typeof raw !== 'number' || !Number.isFinite(raw) || raw <= 0)
|
|
446
|
+
return READER_DEFAULT_LIMIT;
|
|
447
|
+
return Math.min(Math.floor(raw), READER_MAX_LIMIT);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
//# sourceMappingURL=CoherenceJournalReader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CoherenceJournalReader.js","sourceRoot":"","sources":["../../src/core/CoherenceJournalReader.ts"],"names":[],"mappings":"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"}
|