@zelari/core 2.37.3 → 2.38.0
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/README.md +1 -1
- package/dist/core/AgentHarness.d.ts.map +1 -1
- package/dist/core/AgentHarness.js +4 -1
- package/dist/core/AgentHarness.js.map +1 -1
- package/dist/core/requestSnapshot.d.ts +19 -4
- package/dist/core/requestSnapshot.d.ts.map +1 -1
- package/dist/core/requestSnapshot.js +103 -30
- package/dist/core/requestSnapshot.js.map +1 -1
- package/dist/runtime/providers.d.ts +8 -0
- package/dist/runtime/providers.d.ts.map +1 -1
- package/dist/runtime/providers.js.map +1 -1
- package/dist/session/index.d.ts +1 -0
- package/dist/session/index.d.ts.map +1 -1
- package/dist/session/index.js +1 -0
- package/dist/session/index.js.map +1 -1
- package/dist/session/replay.d.ts +18 -0
- package/dist/session/replay.d.ts.map +1 -1
- package/dist/session/replay.js +19 -4
- package/dist/session/replay.js.map +1 -1
- package/dist/session/replayCache.d.ts +76 -0
- package/dist/session/replayCache.d.ts.map +1 -0
- package/dist/session/replayCache.js +188 -0
- package/dist/session/replayCache.js.map +1 -0
- package/dist/verification/commandConcurrency.d.ts +34 -0
- package/dist/verification/commandConcurrency.d.ts.map +1 -0
- package/dist/verification/commandConcurrency.js +45 -0
- package/dist/verification/commandConcurrency.js.map +1 -0
- package/dist/verification/engine.d.ts +25 -0
- package/dist/verification/engine.d.ts.map +1 -1
- package/dist/verification/engine.js +58 -6
- package/dist/verification/engine.js.map +1 -1
- package/dist/verification/index.d.ts +1 -0
- package/dist/verification/index.d.ts.map +1 -1
- package/dist/verification/index.js +1 -0
- package/dist/verification/index.js.map +1 -1
- package/dist/verification/runWithLimit.d.ts +24 -0
- package/dist/verification/runWithLimit.d.ts.map +1 -0
- package/dist/verification/runWithLimit.js +50 -0
- package/dist/verification/runWithLimit.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"providers.js","sourceRoot":"","sources":["../../src/runtime/providers.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,0EAA0E;AAC1E,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IAG/B;IACA;IAHT,IAAI,GAAG,uBAAuB,CAAC;IACxC,YACkB,IAAY,EACZ,SAAiB;QAEjC,KAAK,CAAC,gCAAgC,SAAS,WAAW,IAAI,GAAG,CAAC,CAAC;QAHnD,SAAI,GAAJ,IAAI,CAAQ;QACZ,cAAS,GAAT,SAAS,CAAQ;QAGjC,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;IACzC,CAAC;CACF;AAYD;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,GAAW;IACrD,MAAM,UAAU,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IAChD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,IAAI,QAAQ,KAAK,OAAO,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACrE,MAAM,IAAI,wBAAwB,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IACnD,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,6CAA6C;AAC7C,MAAM,OAAO,cAAc;IAGJ;IAFZ,IAAI,GAAG,OAAgB,CAAC;IAEjC,YAAqB,IAAY;QAAZ,SAAI,GAAJ,IAAI,CAAQ;IAAG,CAAC;IAErC,OAAO,CAAC,GAAW;QACjB,OAAO,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACvC,CAAC;CACF;
|
|
1
|
+
{"version":3,"file":"providers.js","sourceRoot":"","sources":["../../src/runtime/providers.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,0EAA0E;AAC1E,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IAG/B;IACA;IAHT,IAAI,GAAG,uBAAuB,CAAC;IACxC,YACkB,IAAY,EACZ,SAAiB;QAEjC,KAAK,CAAC,gCAAgC,SAAS,WAAW,IAAI,GAAG,CAAC,CAAC;QAHnD,SAAI,GAAJ,IAAI,CAAQ;QACZ,cAAS,GAAT,SAAS,CAAQ;QAGjC,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;IACzC,CAAC;CACF;AAYD;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,GAAW;IACrD,MAAM,UAAU,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IAChD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,IAAI,QAAQ,KAAK,OAAO,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACrE,MAAM,IAAI,wBAAwB,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IACnD,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,6CAA6C;AAC7C,MAAM,OAAO,cAAc;IAGJ;IAFZ,IAAI,GAAG,OAAgB,CAAC;IAEjC,YAAqB,IAAY;QAAZ,SAAI,GAAJ,IAAI,CAAQ;IAAG,CAAC;IAErC,OAAO,CAAC,GAAW;QACjB,OAAO,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACvC,CAAC;CACF;AA0DD,+EAA+E;AAC/E,MAAM,OAAO,oBAAoB;IACtB,SAAS,GAAG,KAAK,CAAC;IAE3B,KAAK,CAAC,OAAO,CAAC,IAAkB;QAC9B,OAAO;YACL,EAAE,EAAE,KAAK;YACT,UAAU,EAAE,+DAA+D,IAAI,CAAC,IAAI,IAAI;SACzF,CAAC;IACJ,CAAC;CACF;AAED,MAAM,CAAC,MAAM,sBAAsB,GAAqB,IAAI,oBAAoB,EAAE,CAAC"}
|
package/dist/session/index.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export * from './compaction.js';
|
|
|
11
11
|
export * from './agentAdapter.js';
|
|
12
12
|
export * from './writer.js';
|
|
13
13
|
export * from './replay.js';
|
|
14
|
+
export * from './replayCache.js';
|
|
14
15
|
export * from './store.js';
|
|
15
16
|
export * from './lineage.js';
|
|
16
17
|
export * from './exportSession.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/session/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/session/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,mBAAmB,CAAC"}
|
package/dist/session/index.js
CHANGED
|
@@ -11,6 +11,7 @@ export * from './compaction.js';
|
|
|
11
11
|
export * from './agentAdapter.js';
|
|
12
12
|
export * from './writer.js';
|
|
13
13
|
export * from './replay.js';
|
|
14
|
+
export * from './replayCache.js';
|
|
14
15
|
export * from './store.js';
|
|
15
16
|
export * from './lineage.js';
|
|
16
17
|
export * from './exportSession.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/session/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/session/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,mBAAmB,CAAC"}
|
package/dist/session/replay.d.ts
CHANGED
|
@@ -24,6 +24,24 @@ export interface ReplayReport {
|
|
|
24
24
|
ok: boolean;
|
|
25
25
|
}
|
|
26
26
|
export declare function readSessionLog(filePath: string): Promise<ReplayReport>;
|
|
27
|
+
/** Whole-file text → ReplayReport (shared with the incremental reader, Int4a). */
|
|
28
|
+
export declare function parseSessionLogText(filePath: string, content: string): ReplayReport;
|
|
29
|
+
/**
|
|
30
|
+
* Parse ONE batch of raw JSONL lines (as produced by `split('\n')`), carrying
|
|
31
|
+
* the running `expected` seq and the 0-based index of the batch's first line.
|
|
32
|
+
* The full reader above and the incremental byte-append reader (replayCache.ts)
|
|
33
|
+
* share this, so both report the SAME events/issues for the same log — that
|
|
34
|
+
* equivalence is the replay-cache contract.
|
|
35
|
+
*/
|
|
36
|
+
export declare function parseSessionLogLines(lines: readonly string[], opts?: {
|
|
37
|
+
expected?: number;
|
|
38
|
+
linesConsumed?: number;
|
|
39
|
+
}): {
|
|
40
|
+
events: SessionEventEnvelope[];
|
|
41
|
+
issues: ReplayIssue[];
|
|
42
|
+
expected: number;
|
|
43
|
+
linesConsumed: number;
|
|
44
|
+
};
|
|
27
45
|
/** Loose summary of a verification.run event (defensive reads). */
|
|
28
46
|
export interface VerificationRunSummary {
|
|
29
47
|
seq: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"replay.d.ts","sourceRoot":"","sources":["../../src/session/replay.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,YAAY,CAAC;AACpB,OAAO,EAAkB,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxE,OAAO,EAA4B,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAE/E,MAAM,MAAM,eAAe,GACvB,cAAc,GACd,iBAAiB,GACjB,eAAe,GACf,SAAS,GACT,kBAAkB,CAAC;AAEvB,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,eAAe,CAAC;IACtB,6CAA6C;IAC7C,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,oBAAoB,EAAE,CAAC;IAC/B,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,4DAA4D;IAC5D,EAAE,EAAE,OAAO,CAAC;CACb;AAED,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,
|
|
1
|
+
{"version":3,"file":"replay.d.ts","sourceRoot":"","sources":["../../src/session/replay.ts"],"names":[],"mappings":"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"}
|
package/dist/session/replay.js
CHANGED
|
@@ -20,15 +20,30 @@ export async function readSessionLog(filePath) {
|
|
|
20
20
|
}
|
|
21
21
|
throw err;
|
|
22
22
|
}
|
|
23
|
+
return parseSessionLogText(filePath, content);
|
|
24
|
+
}
|
|
25
|
+
/** Whole-file text → ReplayReport (shared with the incremental reader, Int4a). */
|
|
26
|
+
export function parseSessionLogText(filePath, content) {
|
|
27
|
+
const { events, issues } = parseSessionLogLines(content.split('\n'));
|
|
28
|
+
return { path: filePath, events, issues, ok: issues.length === 0 };
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Parse ONE batch of raw JSONL lines (as produced by `split('\n')`), carrying
|
|
32
|
+
* the running `expected` seq and the 0-based index of the batch's first line.
|
|
33
|
+
* The full reader above and the incremental byte-append reader (replayCache.ts)
|
|
34
|
+
* share this, so both report the SAME events/issues for the same log — that
|
|
35
|
+
* equivalence is the replay-cache contract.
|
|
36
|
+
*/
|
|
37
|
+
export function parseSessionLogLines(lines, opts = {}) {
|
|
23
38
|
const events = [];
|
|
24
39
|
const issues = [];
|
|
25
|
-
|
|
26
|
-
|
|
40
|
+
const base = opts.linesConsumed ?? 0;
|
|
41
|
+
let expected = opts.expected ?? 1;
|
|
27
42
|
for (let i = 0; i < lines.length; i++) {
|
|
28
43
|
const trimmed = lines[i].trim();
|
|
29
44
|
if (!trimmed)
|
|
30
45
|
continue;
|
|
31
|
-
const lineNo = i + 1;
|
|
46
|
+
const lineNo = base + i + 1;
|
|
32
47
|
let parsed;
|
|
33
48
|
try {
|
|
34
49
|
parsed = JSON.parse(trimmed);
|
|
@@ -65,7 +80,7 @@ export async function readSessionLog(filePath) {
|
|
|
65
80
|
expected = envelope.seq + 1;
|
|
66
81
|
}
|
|
67
82
|
}
|
|
68
|
-
return {
|
|
83
|
+
return { events, issues, expected, linesConsumed: base + lines.length };
|
|
69
84
|
}
|
|
70
85
|
function parseVerification(e) {
|
|
71
86
|
const raw = Array.isArray(e.data.results) ? e.data.results : [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"replay.js","sourceRoot":"","sources":["../../src/session/replay.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EACL,0BAA0B,GAE3B,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,cAAc,EAAuB,MAAM,mBAAmB,CAAC;AACxE,OAAO,EAAE,wBAAwB,EAAwB,MAAM,eAAe,CAAC;AAyB/E,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,QAAgB;IACnD,IAAI,OAAe,CAAC;IACpB,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACjD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACrD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;QAC9D,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;IACD,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,MAAM,MAAM,GAAkB,EAAE,CAAC;IACjC,IAAI,
|
|
1
|
+
{"version":3,"file":"replay.js","sourceRoot":"","sources":["../../src/session/replay.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* session/replayCache.ts — Int4a incremental replay cache for long sessions.
|
|
3
|
+
*
|
|
4
|
+
* `readSessionLog()` re-reads the WHOLE JSONL and Zod-parses every line on
|
|
5
|
+
* every call, and the spine does it 2–8 times per turn: O(n²) in session
|
|
6
|
+
* length. This cache keeps the parsed events per file and, on a later call,
|
|
7
|
+
* reads only the bytes appended since the last read (COMPLETE lines only).
|
|
8
|
+
*
|
|
9
|
+
* Invariants:
|
|
10
|
+
* - `byteSize` is what the entry OWNS: every complete line consumed plus the
|
|
11
|
+
* bytes held in `partial`. It always sits on a UTF-8 character boundary, so
|
|
12
|
+
* the next read starts exactly there and no byte is ever parsed twice.
|
|
13
|
+
* - A tail without its final '\n' stays in `partial` and is NOT an event yet:
|
|
14
|
+
* it appears exactly once, when the writer completes the line. A tail
|
|
15
|
+
* ending INSIDE a multi-byte character is not consumed at all (re-read from
|
|
16
|
+
* a boundary) — a torn write can never poison the cache with U+FFFD.
|
|
17
|
+
* - Shrink (`size < byteSize`) or a backwards mtime (rotation / in-place
|
|
18
|
+
* rewrite) ⇒ full re-read through the SAME parse path as `readSessionLog`,
|
|
19
|
+
* so a replaced log is never served from stale entries.
|
|
20
|
+
* - The returned ReplayReport is fresh (caller-owned arrays); the envelopes
|
|
21
|
+
* inside are shared and treat-as-immutable — the spine contract.
|
|
22
|
+
* - Known deviation: a COLD read (empty cache / rotation) consumes a
|
|
23
|
+
* non-terminated last line exactly as `readSessionLog` does today; only
|
|
24
|
+
* appends observed while warm are deferred into `partial`. The writer
|
|
25
|
+
* always terminates lines with '\n', so this needs external truncation.
|
|
26
|
+
*
|
|
27
|
+
* Kill switch `ZELARI_SPINE_REPLAY_CACHE`: DEFAULT OFF in this merge (dogfood
|
|
28
|
+
* first) — set `1`/`true`/`yes`/`on` to enable. When unset/0/false/off,
|
|
29
|
+
* `readSessionLogCached` calls the existing `readSessionLog` verbatim.
|
|
30
|
+
*/
|
|
31
|
+
import { type ReplayIssue, type ReplayReport } from './replay.js';
|
|
32
|
+
import type { SessionEventEnvelope } from './types.js';
|
|
33
|
+
/** `ZELARI_SPINE_REPLAY_CACHE` (default OFF): truthy spelling = 1/true/yes/on. */
|
|
34
|
+
export declare function isReplayCacheEnabled(env?: NodeJS.ProcessEnv): boolean;
|
|
35
|
+
export interface ReplayCacheEntry {
|
|
36
|
+
/** Bytes owned by this entry: complete lines + the bytes held in `partial`. */
|
|
37
|
+
byteSize: number;
|
|
38
|
+
mtimeMs: number;
|
|
39
|
+
events: SessionEventEnvelope[];
|
|
40
|
+
issues: ReplayIssue[];
|
|
41
|
+
/** Seq the next event must carry to be accepted gap-free. */
|
|
42
|
+
expectedSeq: number;
|
|
43
|
+
/** Tail without a final '\n' (writer crash mid-line) — not yet an event. */
|
|
44
|
+
partial: string;
|
|
45
|
+
/**
|
|
46
|
+
* Lines consumed so far, blank/corrupt ones included, so a new issue keeps
|
|
47
|
+
* its ORIGINAL 1-based file line number (`linesConsumed + index + 1`).
|
|
48
|
+
* Additive to the planned entry shape: without it an incremental read would
|
|
49
|
+
* renumber issues and stop being equivalent to `readSessionLog`.
|
|
50
|
+
*/
|
|
51
|
+
linesConsumed: number;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Incremental replay cache. Own ONE instance per session (the spine mirror owns
|
|
55
|
+
* its own); entries are keyed by file path, so concurrent sessions never share
|
|
56
|
+
* decoded state.
|
|
57
|
+
*/
|
|
58
|
+
export declare class SessionLogCache {
|
|
59
|
+
private readonly entries;
|
|
60
|
+
/** Files currently cached (diagnostics). */
|
|
61
|
+
get size(): number;
|
|
62
|
+
/** The cached entry for `filePath` (copy; tests + diagnostics), if any. */
|
|
63
|
+
peek(filePath: string): ReplayCacheEntry | undefined;
|
|
64
|
+
/** Read the log, incrementally when a usable entry exists. */
|
|
65
|
+
read(filePath: string): Promise<ReplayReport>;
|
|
66
|
+
/** Append-path read: only the bytes written since the last read are parsed. */
|
|
67
|
+
private extend;
|
|
68
|
+
/** Cold / rotated read: same parse as `readSessionLog`, then seed the entry. */
|
|
69
|
+
private full;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Cached read of a session log. Without a cache — or with the kill switch off
|
|
73
|
+
* (the default in this merge) — this is `readSessionLog` verbatim.
|
|
74
|
+
*/
|
|
75
|
+
export declare function readSessionLogCached(filePath: string, cache?: SessionLogCache, env?: NodeJS.ProcessEnv): Promise<ReplayReport>;
|
|
76
|
+
//# sourceMappingURL=replayCache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replayCache.d.ts","sourceRoot":"","sources":["../../src/session/replayCache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAGH,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,YAAY,EAClB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAMvD,kFAAkF;AAClF,wBAAgB,oBAAoB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAGlF;AAED,MAAM,WAAW,gBAAgB;IAC/B,+EAA+E;IAC/E,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,oBAAoB,EAAE,CAAC;IAC/B,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,6DAA6D;IAC7D,WAAW,EAAE,MAAM,CAAC;IACpB,4EAA4E;IAC5E,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,aAAa,EAAE,MAAM,CAAC;CACvB;AAuCD;;;;GAIG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuC;IAE/D,4CAA4C;IAC5C,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,2EAA2E;IAC3E,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS;IAKpD,8DAA8D;IACxD,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAmBnD,+EAA+E;YACjE,MAAM;IAwCpB,gFAAgF;YAClE,IAAI;CA6BnB;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,MAAM,EAChB,KAAK,CAAC,EAAE,eAAe,EACvB,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,OAAO,CAAC,YAAY,CAAC,CAGvB"}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* session/replayCache.ts — Int4a incremental replay cache for long sessions.
|
|
3
|
+
*
|
|
4
|
+
* `readSessionLog()` re-reads the WHOLE JSONL and Zod-parses every line on
|
|
5
|
+
* every call, and the spine does it 2–8 times per turn: O(n²) in session
|
|
6
|
+
* length. This cache keeps the parsed events per file and, on a later call,
|
|
7
|
+
* reads only the bytes appended since the last read (COMPLETE lines only).
|
|
8
|
+
*
|
|
9
|
+
* Invariants:
|
|
10
|
+
* - `byteSize` is what the entry OWNS: every complete line consumed plus the
|
|
11
|
+
* bytes held in `partial`. It always sits on a UTF-8 character boundary, so
|
|
12
|
+
* the next read starts exactly there and no byte is ever parsed twice.
|
|
13
|
+
* - A tail without its final '\n' stays in `partial` and is NOT an event yet:
|
|
14
|
+
* it appears exactly once, when the writer completes the line. A tail
|
|
15
|
+
* ending INSIDE a multi-byte character is not consumed at all (re-read from
|
|
16
|
+
* a boundary) — a torn write can never poison the cache with U+FFFD.
|
|
17
|
+
* - Shrink (`size < byteSize`) or a backwards mtime (rotation / in-place
|
|
18
|
+
* rewrite) ⇒ full re-read through the SAME parse path as `readSessionLog`,
|
|
19
|
+
* so a replaced log is never served from stale entries.
|
|
20
|
+
* - The returned ReplayReport is fresh (caller-owned arrays); the envelopes
|
|
21
|
+
* inside are shared and treat-as-immutable — the spine contract.
|
|
22
|
+
* - Known deviation: a COLD read (empty cache / rotation) consumes a
|
|
23
|
+
* non-terminated last line exactly as `readSessionLog` does today; only
|
|
24
|
+
* appends observed while warm are deferred into `partial`. The writer
|
|
25
|
+
* always terminates lines with '\n', so this needs external truncation.
|
|
26
|
+
*
|
|
27
|
+
* Kill switch `ZELARI_SPINE_REPLAY_CACHE`: DEFAULT OFF in this merge (dogfood
|
|
28
|
+
* first) — set `1`/`true`/`yes`/`on` to enable. When unset/0/false/off,
|
|
29
|
+
* `readSessionLogCached` calls the existing `readSessionLog` verbatim.
|
|
30
|
+
*/
|
|
31
|
+
import { promises as fs } from 'node:fs';
|
|
32
|
+
import { readSessionLog, parseSessionLogLines, } from './replay.js';
|
|
33
|
+
/** `ZELARI_SPINE_REPLAY_CACHE` (default OFF): truthy spelling = 1/true/yes/on. */
|
|
34
|
+
export function isReplayCacheEnabled(env = process.env) {
|
|
35
|
+
const v = (env.ZELARI_SPINE_REPLAY_CACHE ?? '').trim().toLowerCase();
|
|
36
|
+
return v === '1' || v === 'true' || v === 'yes' || v === 'on';
|
|
37
|
+
}
|
|
38
|
+
const NL = 0x0a;
|
|
39
|
+
/** >0 when `buf` ends inside a multi-byte UTF-8 sequence (bytes to leave unread). */
|
|
40
|
+
function utf8IncompleteTailBytes(buf) {
|
|
41
|
+
const max = Math.min(4, buf.length);
|
|
42
|
+
for (let back = 1; back <= max; back++) {
|
|
43
|
+
const b = buf[buf.length - back];
|
|
44
|
+
if (b < 0x80)
|
|
45
|
+
return 0; // ASCII tail — complete
|
|
46
|
+
if (b >= 0xc0) {
|
|
47
|
+
// Lead byte: it must be followed by (need - 1) continuation bytes.
|
|
48
|
+
const need = b >= 0xf0 ? 4 : b >= 0xe0 ? 3 : 2;
|
|
49
|
+
return back >= need ? 0 : need - back;
|
|
50
|
+
}
|
|
51
|
+
// 0x80..0xbf = continuation byte — walk back to its lead byte.
|
|
52
|
+
}
|
|
53
|
+
return 0; // no lead byte within 4 bytes: malformed anyway, let JSON.parse judge
|
|
54
|
+
}
|
|
55
|
+
/** Read exactly `length` bytes at `position` (a live writer may shorten reads). */
|
|
56
|
+
async function readAt(fh, position, length) {
|
|
57
|
+
const buf = Buffer.allocUnsafe(length);
|
|
58
|
+
let done = 0;
|
|
59
|
+
while (done < length) {
|
|
60
|
+
const { bytesRead } = await fh.read(buf, done, length - done, position + done);
|
|
61
|
+
if (bytesRead === 0)
|
|
62
|
+
break; // truncated under us — parse what we got
|
|
63
|
+
done += bytesRead;
|
|
64
|
+
}
|
|
65
|
+
return done === length ? buf : buf.subarray(0, done);
|
|
66
|
+
}
|
|
67
|
+
/** Fresh report over the cached arrays — a consumer may mutate them freely. */
|
|
68
|
+
function toReport(filePath, entry) {
|
|
69
|
+
const events = entry.events.slice();
|
|
70
|
+
const issues = entry.issues.slice();
|
|
71
|
+
return { path: filePath, events, issues, ok: issues.length === 0 };
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Incremental replay cache. Own ONE instance per session (the spine mirror owns
|
|
75
|
+
* its own); entries are keyed by file path, so concurrent sessions never share
|
|
76
|
+
* decoded state.
|
|
77
|
+
*/
|
|
78
|
+
export class SessionLogCache {
|
|
79
|
+
entries = new Map();
|
|
80
|
+
/** Files currently cached (diagnostics). */
|
|
81
|
+
get size() {
|
|
82
|
+
return this.entries.size;
|
|
83
|
+
}
|
|
84
|
+
/** The cached entry for `filePath` (copy; tests + diagnostics), if any. */
|
|
85
|
+
peek(filePath) {
|
|
86
|
+
const entry = this.entries.get(filePath);
|
|
87
|
+
return entry ? { ...entry } : undefined;
|
|
88
|
+
}
|
|
89
|
+
/** Read the log, incrementally when a usable entry exists. */
|
|
90
|
+
async read(filePath) {
|
|
91
|
+
const cached = this.entries.get(filePath);
|
|
92
|
+
let stat;
|
|
93
|
+
try {
|
|
94
|
+
stat = await fs.stat(filePath);
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
if (err.code === 'ENOENT') {
|
|
98
|
+
this.entries.delete(filePath);
|
|
99
|
+
return { path: filePath, events: [], issues: [], ok: true };
|
|
100
|
+
}
|
|
101
|
+
throw err;
|
|
102
|
+
}
|
|
103
|
+
if (cached && stat.size >= cached.byteSize && stat.mtimeMs >= cached.mtimeMs) {
|
|
104
|
+
if (stat.size > cached.byteSize)
|
|
105
|
+
return this.extend(filePath, cached, stat);
|
|
106
|
+
return toReport(filePath, cached); // nothing new — no I/O at all
|
|
107
|
+
}
|
|
108
|
+
return this.full(filePath, stat);
|
|
109
|
+
}
|
|
110
|
+
/** Append-path read: only the bytes written since the last read are parsed. */
|
|
111
|
+
async extend(filePath, cached, stat) {
|
|
112
|
+
const fh = await fs.open(filePath, 'r');
|
|
113
|
+
let chunk;
|
|
114
|
+
try {
|
|
115
|
+
chunk = await readAt(fh, cached.byteSize, stat.size - cached.byteSize);
|
|
116
|
+
}
|
|
117
|
+
finally {
|
|
118
|
+
await fh.close();
|
|
119
|
+
}
|
|
120
|
+
const nl = chunk.lastIndexOf(NL);
|
|
121
|
+
const headEnd = nl === -1 ? 0 : nl + 1; // end of the last COMPLETE line
|
|
122
|
+
const tail = chunk.subarray(headEnd);
|
|
123
|
+
// PERF-4a: bytes of the tail that decode cleanly. A tail ending INSIDE a
|
|
124
|
+
// multi-byte char stays unconsumed and is re-read from a boundary, so
|
|
125
|
+
// `partial` is never a U+FFFD-mangled fragment.
|
|
126
|
+
const keep = tail.subarray(0, tail.length - utf8IncompleteTailBytes(tail));
|
|
127
|
+
// The old `partial` is folded into `head` only once a newline arrives; while
|
|
128
|
+
// no line completes it stays in front of the unconsumed tail.
|
|
129
|
+
const head = cached.partial + chunk.subarray(0, headEnd).toString('utf8');
|
|
130
|
+
const lines = headEnd > 0 ? head.split('\n').slice(0, -1) : [];
|
|
131
|
+
const parsed = parseSessionLogLines(lines, {
|
|
132
|
+
expected: cached.expectedSeq,
|
|
133
|
+
linesConsumed: cached.linesConsumed,
|
|
134
|
+
});
|
|
135
|
+
const entry = {
|
|
136
|
+
byteSize: cached.byteSize + headEnd + keep.length,
|
|
137
|
+
mtimeMs: stat.mtimeMs,
|
|
138
|
+
events: parsed.events.length > 0 ? cached.events.concat(parsed.events) : cached.events,
|
|
139
|
+
issues: parsed.issues.length > 0 ? cached.issues.concat(parsed.issues) : cached.issues,
|
|
140
|
+
expectedSeq: parsed.expected,
|
|
141
|
+
partial: (headEnd > 0 ? '' : cached.partial) + keep.toString('utf8'),
|
|
142
|
+
linesConsumed: parsed.linesConsumed,
|
|
143
|
+
};
|
|
144
|
+
this.entries.set(filePath, entry);
|
|
145
|
+
return toReport(filePath, entry);
|
|
146
|
+
}
|
|
147
|
+
/** Cold / rotated read: same parse as `readSessionLog`, then seed the entry. */
|
|
148
|
+
async full(filePath, stat) {
|
|
149
|
+
let content;
|
|
150
|
+
try {
|
|
151
|
+
content = await fs.readFile(filePath, 'utf-8');
|
|
152
|
+
}
|
|
153
|
+
catch (err) {
|
|
154
|
+
if (err.code === 'ENOENT') {
|
|
155
|
+
this.entries.delete(filePath);
|
|
156
|
+
return { path: filePath, events: [], issues: [], ok: true };
|
|
157
|
+
}
|
|
158
|
+
throw err;
|
|
159
|
+
}
|
|
160
|
+
const lines = content.split('\n');
|
|
161
|
+
const parsed = parseSessionLogLines(lines);
|
|
162
|
+
// Count the lines this read consumed: the split's trailing '' is the
|
|
163
|
+
// artificial piece after the final '\n'; a torn tail is already parsed.
|
|
164
|
+
const linesConsumed = content.length === 0 ? 0 : content.endsWith('\n') ? lines.length - 1 : lines.length;
|
|
165
|
+
const entry = {
|
|
166
|
+
// Bytes actually read (never the pre-read stat: the log may have grown).
|
|
167
|
+
byteSize: Buffer.byteLength(content, 'utf8'),
|
|
168
|
+
mtimeMs: stat.mtimeMs,
|
|
169
|
+
events: parsed.events,
|
|
170
|
+
issues: parsed.issues,
|
|
171
|
+
expectedSeq: parsed.expected,
|
|
172
|
+
partial: '',
|
|
173
|
+
linesConsumed,
|
|
174
|
+
};
|
|
175
|
+
this.entries.set(filePath, entry);
|
|
176
|
+
return { path: filePath, events: entry.events.slice(), issues: entry.issues.slice(), ok: entry.issues.length === 0 };
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Cached read of a session log. Without a cache — or with the kill switch off
|
|
181
|
+
* (the default in this merge) — this is `readSessionLog` verbatim.
|
|
182
|
+
*/
|
|
183
|
+
export async function readSessionLogCached(filePath, cache, env = process.env) {
|
|
184
|
+
if (!cache || !isReplayCacheEnabled(env))
|
|
185
|
+
return readSessionLog(filePath);
|
|
186
|
+
return cache.read(filePath);
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=replayCache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replayCache.js","sourceRoot":"","sources":["../../src/session/replayCache.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* verification/commandConcurrency.ts — Int2a gate fan-out policy (ADR-0023).
|
|
3
|
+
*
|
|
4
|
+
* A criteria pack runs independent PROCESSES (typecheck / test / build) that
|
|
5
|
+
* are not independent WRITES: on this repo `test` rebuilds `@zelari/core` into
|
|
6
|
+
* `packages/core/dist` while `build` cleans the very same path, so a parallel
|
|
7
|
+
* run can read a partial `dist` and produce flaky FAILs. Fail-closed is not
|
|
8
|
+
* good enough — a flaky gate destroys trust in strict-done exactly like a
|
|
9
|
+
* false PASS does, so fan-out is OPT-IN per repo and OFF by default.
|
|
10
|
+
*
|
|
11
|
+
* ZELARI_VERIFY_PARALLEL 1|true|yes|on → bounded parallel evaluation of
|
|
12
|
+
* command criteria (anything else → sequential)
|
|
13
|
+
* ZELARI_VERIFY_CONCURRENCY max commands in flight, default 3
|
|
14
|
+
*
|
|
15
|
+
* Kill-switch: unset, `0` or any unrecognized value → 1, i.e. the sequential
|
|
16
|
+
* `for...of` path this engine has always used (same order, same events).
|
|
17
|
+
*
|
|
18
|
+
* @since v2.38.x
|
|
19
|
+
*/
|
|
20
|
+
/** Only used when parallelism is explicitly enabled and no limit is given. */
|
|
21
|
+
export declare const DEFAULT_COMMAND_CONCURRENCY = 3;
|
|
22
|
+
/**
|
|
23
|
+
* Parallel evaluation is opt-in: `1|true|yes|on` (case/space insensitive)
|
|
24
|
+
* enables it, everything else — including unset — keeps the gate sequential.
|
|
25
|
+
*/
|
|
26
|
+
export declare function isVerifyParallelEnabled(env?: Record<string, string | undefined>): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Effective max number of command criteria in flight: `1` unless parallelism
|
|
29
|
+
* is enabled. `ZELARI_VERIFY_CONCURRENCY` is only consulted when enabled and
|
|
30
|
+
* is clamped to >= 1 (a bad value can never deadlock or fan out unbounded —
|
|
31
|
+
* the runner additionally clamps to the number of criteria).
|
|
32
|
+
*/
|
|
33
|
+
export declare function resolveCommandConcurrency(env?: Record<string, string | undefined>): number;
|
|
34
|
+
//# sourceMappingURL=commandConcurrency.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commandConcurrency.d.ts","sourceRoot":"","sources":["../../src/verification/commandConcurrency.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,8EAA8E;AAC9E,eAAO,MAAM,2BAA2B,IAAI,CAAC;AAI7C;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GACpD,OAAO,CAGT;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GACpD,MAAM,CAKR"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* verification/commandConcurrency.ts — Int2a gate fan-out policy (ADR-0023).
|
|
3
|
+
*
|
|
4
|
+
* A criteria pack runs independent PROCESSES (typecheck / test / build) that
|
|
5
|
+
* are not independent WRITES: on this repo `test` rebuilds `@zelari/core` into
|
|
6
|
+
* `packages/core/dist` while `build` cleans the very same path, so a parallel
|
|
7
|
+
* run can read a partial `dist` and produce flaky FAILs. Fail-closed is not
|
|
8
|
+
* good enough — a flaky gate destroys trust in strict-done exactly like a
|
|
9
|
+
* false PASS does, so fan-out is OPT-IN per repo and OFF by default.
|
|
10
|
+
*
|
|
11
|
+
* ZELARI_VERIFY_PARALLEL 1|true|yes|on → bounded parallel evaluation of
|
|
12
|
+
* command criteria (anything else → sequential)
|
|
13
|
+
* ZELARI_VERIFY_CONCURRENCY max commands in flight, default 3
|
|
14
|
+
*
|
|
15
|
+
* Kill-switch: unset, `0` or any unrecognized value → 1, i.e. the sequential
|
|
16
|
+
* `for...of` path this engine has always used (same order, same events).
|
|
17
|
+
*
|
|
18
|
+
* @since v2.38.x
|
|
19
|
+
*/
|
|
20
|
+
/** Only used when parallelism is explicitly enabled and no limit is given. */
|
|
21
|
+
export const DEFAULT_COMMAND_CONCURRENCY = 3;
|
|
22
|
+
const PARALLEL_TRUTHY = new Set(['1', 'true', 'yes', 'on']);
|
|
23
|
+
/**
|
|
24
|
+
* Parallel evaluation is opt-in: `1|true|yes|on` (case/space insensitive)
|
|
25
|
+
* enables it, everything else — including unset — keeps the gate sequential.
|
|
26
|
+
*/
|
|
27
|
+
export function isVerifyParallelEnabled(env = process.env) {
|
|
28
|
+
const raw = env.ZELARI_VERIFY_PARALLEL?.trim().toLowerCase();
|
|
29
|
+
return raw !== undefined && PARALLEL_TRUTHY.has(raw);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Effective max number of command criteria in flight: `1` unless parallelism
|
|
33
|
+
* is enabled. `ZELARI_VERIFY_CONCURRENCY` is only consulted when enabled and
|
|
34
|
+
* is clamped to >= 1 (a bad value can never deadlock or fan out unbounded —
|
|
35
|
+
* the runner additionally clamps to the number of criteria).
|
|
36
|
+
*/
|
|
37
|
+
export function resolveCommandConcurrency(env = process.env) {
|
|
38
|
+
if (!isVerifyParallelEnabled(env))
|
|
39
|
+
return 1;
|
|
40
|
+
const raw = Number(env.ZELARI_VERIFY_CONCURRENCY);
|
|
41
|
+
if (!Number.isFinite(raw) || raw <= 0)
|
|
42
|
+
return DEFAULT_COMMAND_CONCURRENCY;
|
|
43
|
+
return Math.floor(raw);
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=commandConcurrency.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commandConcurrency.js","sourceRoot":"","sources":["../../src/verification/commandConcurrency.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,8EAA8E;AAC9E,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,CAAC;AAE7C,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;AAE5D;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CACrC,MAA0C,OAAO,CAAC,GAAG;IAErD,MAAM,GAAG,GAAG,GAAG,CAAC,sBAAsB,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC7D,OAAO,GAAG,KAAK,SAAS,IAAI,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AACvD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,yBAAyB,CACvC,MAA0C,OAAO,CAAC,GAAG;IAErD,IAAI,CAAC,uBAAuB,CAAC,GAAG,CAAC;QAAE,OAAO,CAAC,CAAC;IAC5C,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;IAClD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;QAAE,OAAO,2BAA2B,CAAC;IAC1E,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AACzB,CAAC"}
|
|
@@ -12,6 +12,23 @@
|
|
|
12
12
|
* output tails) and, when the emitter resolves to the appended envelope, the
|
|
13
13
|
* assigned seq anchors the EvidenceRef — evidence is traceable to the
|
|
14
14
|
* session event that captured it, not to a narrated summary.
|
|
15
|
+
*
|
|
16
|
+
* Int2b: when the injected shell is decorated with a result cache (see
|
|
17
|
+
* `src/cli/kraken/cachedShell.ts`), a served-from-cache observation is
|
|
18
|
+
* ANNOTATED, never reinterpreted — `detail` gains a " (cached — tree unchanged
|
|
19
|
+
* since last run)" suffix and the evidence event carries an optional
|
|
20
|
+
* `cached: true`. Status, digest and evidence payload shape are untouched, so
|
|
21
|
+
* caching can change the latency of a verdict but never the verdict.
|
|
22
|
+
*
|
|
23
|
+
* Int2a: command criteria MAY be evaluated concurrently with a bounded
|
|
24
|
+
* fan-out (`commandConcurrency`, default OFF — see `./commandConcurrency.ts`).
|
|
25
|
+
* Parallelism is about `evaluateOne` concurrency, the cache is about shell
|
|
26
|
+
* exec reuse; they compose. Only the LATENCY changes: results keep the
|
|
27
|
+
* criteria order of `verification.run`, and `verification.evidence` events may
|
|
28
|
+
* interleave because each ref is anchored to its OWN event seq (a seq anchors
|
|
29
|
+
* an observation, it never depends on the position of the event in the log).
|
|
30
|
+
* When the fan-out is 1 (default, or the kill-switch) the loop below is the
|
|
31
|
+
* untouched sequential path.
|
|
15
32
|
*/
|
|
16
33
|
import type { FsProvider, ShellProvider } from '../runtime/providers.js';
|
|
17
34
|
import type { SessionEventInput } from '../session/types.js';
|
|
@@ -30,6 +47,14 @@ export interface VerificationEngineOptions {
|
|
|
30
47
|
emit?: (input: SessionEventInput) => Promise<unknown>;
|
|
31
48
|
now?: () => number;
|
|
32
49
|
sha256?: (input: string) => string;
|
|
50
|
+
/**
|
|
51
|
+
* Max command criteria evaluated concurrently. `undefined` (the default)
|
|
52
|
+
* resolves through `resolveCommandConcurrency()` — i.e. 1 unless the
|
|
53
|
+
* environment opts in via `ZELARI_VERIFY_PARALLEL=1`. `<= 1` always means
|
|
54
|
+
* the plain sequential loop; a host that wires the flag explicitly should
|
|
55
|
+
* keep passing a value here.
|
|
56
|
+
*/
|
|
57
|
+
commandConcurrency?: number;
|
|
33
58
|
}
|
|
34
59
|
export declare class VerificationEngine {
|
|
35
60
|
private readonly services;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/verification/engine.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/verification/engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,KAAK,EAAE,SAAS,EAAe,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAC7E,OAAO,EAAgB,KAAK,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAI7E,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,EAAE,CAAC,EAAE,UAAU,CAAC;CACjB;AAED,MAAM,WAAW,yBAAyB;IACxC;;;;OAIG;IACH,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACtD,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACnC;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAkBD,qBAAa,kBAAkB;IAE3B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBADP,QAAQ,GAAE,oBAAyB,EACnC,OAAO,GAAE,yBAA8B;IAG1D,4EAA4E;IACtE,QAAQ,CACZ,QAAQ,EAAE,SAAS,SAAS,EAAE,EAC9B,OAAO,GAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,kBAAkB,CAAA;KAAO,GAC5D,OAAO,CAAC,kBAAkB,EAAE,CAAC;IA4ChC;;;;;OAKG;YACW,YAAY;YAiBZ,WAAW;YAmDX,WAAW;IAqEzB;;;;OAIG;YACW,UAAU;YAkBV,cAAc;YAmBd,cAAc;YAiBd,gBAAgB;CAyB/B"}
|