@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.
Files changed (42) hide show
  1. package/README.md +1 -1
  2. package/dist/core/AgentHarness.d.ts.map +1 -1
  3. package/dist/core/AgentHarness.js +4 -1
  4. package/dist/core/AgentHarness.js.map +1 -1
  5. package/dist/core/requestSnapshot.d.ts +19 -4
  6. package/dist/core/requestSnapshot.d.ts.map +1 -1
  7. package/dist/core/requestSnapshot.js +103 -30
  8. package/dist/core/requestSnapshot.js.map +1 -1
  9. package/dist/runtime/providers.d.ts +8 -0
  10. package/dist/runtime/providers.d.ts.map +1 -1
  11. package/dist/runtime/providers.js.map +1 -1
  12. package/dist/session/index.d.ts +1 -0
  13. package/dist/session/index.d.ts.map +1 -1
  14. package/dist/session/index.js +1 -0
  15. package/dist/session/index.js.map +1 -1
  16. package/dist/session/replay.d.ts +18 -0
  17. package/dist/session/replay.d.ts.map +1 -1
  18. package/dist/session/replay.js +19 -4
  19. package/dist/session/replay.js.map +1 -1
  20. package/dist/session/replayCache.d.ts +76 -0
  21. package/dist/session/replayCache.d.ts.map +1 -0
  22. package/dist/session/replayCache.js +188 -0
  23. package/dist/session/replayCache.js.map +1 -0
  24. package/dist/verification/commandConcurrency.d.ts +34 -0
  25. package/dist/verification/commandConcurrency.d.ts.map +1 -0
  26. package/dist/verification/commandConcurrency.js +45 -0
  27. package/dist/verification/commandConcurrency.js.map +1 -0
  28. package/dist/verification/engine.d.ts +25 -0
  29. package/dist/verification/engine.d.ts.map +1 -1
  30. package/dist/verification/engine.js +58 -6
  31. package/dist/verification/engine.js.map +1 -1
  32. package/dist/verification/index.d.ts +1 -0
  33. package/dist/verification/index.d.ts.map +1 -1
  34. package/dist/verification/index.js +1 -0
  35. package/dist/verification/index.js.map +1 -1
  36. package/dist/verification/runWithLimit.d.ts +24 -0
  37. package/dist/verification/runWithLimit.d.ts.map +1 -0
  38. package/dist/verification/runWithLimit.js +50 -0
  39. package/dist/verification/runWithLimit.js.map +1 -0
  40. package/dist/version.d.ts +1 -1
  41. package/dist/version.js +1 -1
  42. 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;AAkDD,+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"}
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"}
@@ -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"}
@@ -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"}
@@ -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,CAoD5E;AAED,mEAAmE;AACnE,MAAM,WAAW,sBAAsB;IACrC,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,KAAK,CAAC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/E,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE;QAAE,eAAe,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IACtD,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,sBAAsB,EAAE,CAAC;IACxC,aAAa,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACrD,0EAA0E;IAC1E,aAAa,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjF,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,uEAAuE;IACvE,gBAAgB,EAAE,eAAe,EAAE,CAAC;CACrC;AAmBD,wEAAwE;AACxE,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,oBAAoB,EAAE,EAAE,MAAM,GAAE,WAAW,EAAO,GAAG,iBAAiB,CA4DtH"}
1
+ {"version":3,"file":"replay.d.ts","sourceRoot":"","sources":["../../src/session/replay.ts"],"names":[],"mappings":"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"}
@@ -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
- let expected = 1;
26
- const lines = content.split('\n');
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 { path: filePath, events, issues, ok: issues.length === 0 };
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,QAAQ,GAAG,CAAC,CAAC;IACjB,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAClC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAChC,IAAI,CAAC,OAAO;YAAE,SAAS;QACvB,MAAM,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC;QACrB,IAAI,MAAe,CAAC;QACpB,IAAI,CAAC;YACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC/B,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;YACpD,SAAS;QACX,CAAC;QACD,MAAM,MAAM,GAAG,0BAA0B,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAC5D,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,iBAAiB;gBACvB,IAAI,EAAE,MAAM;gBACZ,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,OAAO,IAAI,0BAA0B;aACtE,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QACD,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC;QAC7B,IAAI,QAAQ,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;YAC9B,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACtB,QAAQ,IAAI,CAAC,CAAC;QAChB,CAAC;aAAM,IAAI,QAAQ,CAAC,GAAG,GAAG,QAAQ,EAAE,CAAC;YACnC,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC;QAC1E,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,MAAM;gBACZ,GAAG,EAAE,QAAQ,CAAC,GAAG;gBACjB,MAAM,EAAE,eAAe,QAAQ,KAAK,QAAQ,CAAC,GAAG,GAAG,CAAC,EAAE;aACvD,CAAC,CAAC;YACH,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACtB,QAAQ,GAAG,QAAQ,CAAC,GAAG,GAAG,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;AACrE,CAAC;AA+BD,SAAS,iBAAiB,CAAC,CAAuB;IAChD,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;IAChE,MAAM,OAAO,GAAG,GAAG;SAChB,MAAM,CAAC,CAAC,CAAC,EAAgC,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,CAAC;SAChF,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACX,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC,WAAW,IAAI,SAAS,CAAC;QAC/C,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,IAAI,SAAS,CAAC;QACrC,aAAa,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;KACjE,CAAC,CAAC,CAAC;IACN,OAAO;QACL,GAAG,EAAE,CAAC,CAAC,GAAG;QACV,EAAE,EAAE,CAAC,CAAC,EAAE;QACR,OAAO;QACP,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;KAC7E,CAAC;AACJ,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,eAAe,CAAC,MAAuC,EAAE,SAAwB,EAAE;IACjG,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACvC,MAAM,UAAU,GAAsB;QACpC,SAAS,EAAE,IAAI,EAAE,SAAS,IAAI,EAAE;QAChC,OAAO,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC;QACvB,UAAU,EAAE,MAAM,CAAC,MAAM;QACzB,YAAY,EAAE,CAAC;QACf,QAAQ,EAAE,cAAc,CAAC,MAAM,CAAC;QAChC,SAAS,EAAE,CAAC;QACZ,WAAW,EAAE,CAAC;QACd,aAAa,EAAE,EAAE;QACjB,aAAa,EAAE,EAAE;QACjB,aAAa,EAAE,EAAE;QACjB,OAAO,EAAE,CAAC;QACV,MAAM;QACN,gBAAgB,EAAE,wBAAwB,CAAC,MAAM,CAAC;KACnD,CAAC;IACF,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;YACf,KAAK,iBAAiB;gBACpB,UAAU,CAAC,SAAS,GAAG,CAAC,CAAC,EAAE,CAAC;gBAC5B,MAAM;YACR,KAAK,eAAe;gBAClB,UAAU,CAAC,OAAO,GAAG,CAAC,CAAC,EAAE,CAAC;gBAC1B,MAAM;YACR,KAAK,iBAAiB;gBACpB,UAAU,CAAC,YAAY,IAAI,CAAC,CAAC;gBAC7B,MAAM;YACR,KAAK,gBAAgB;gBACnB,UAAU,CAAC,IAAI,GAAG;oBAChB,eAAe,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,IAAI,EAAE,CAAC;oBACrD,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,CAAC;iBACzC,CAAC;gBACF,MAAM;YACR,KAAK,WAAW;gBACd,UAAU,CAAC,SAAS,IAAI,CAAC,CAAC;gBAC1B,MAAM;YACR,KAAK,aAAa;gBAChB,UAAU,CAAC,WAAW,IAAI,CAAC,CAAC;gBAC5B,MAAM;YACR,KAAK,kBAAkB;gBACrB,UAAU,CAAC,aAAa,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC;gBACpD,MAAM;YACR,KAAK,eAAe;gBAClB,UAAU,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;gBACjF,MAAM;YACR,KAAK,gBAAgB;gBACnB,UAAU,CAAC,OAAO,IAAI,CAAC,CAAC;gBACxB,MAAM;YACR,KAAK,kBAAkB;gBACrB,UAAU,CAAC,aAAa,CAAC,IAAI,CAAC;oBAC5B,GAAG,EAAE,CAAC,CAAC,GAAG;oBACV,cAAc,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,IAAI,EAAE,CAAC;oBACnD,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC;iBAC1C,CAAC,CAAC;gBACH,MAAM;gBACN,MAAM;QACV,CAAC;IACH,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC"}
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;;;;;;;;;;;;;;GAcG;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;AAE7E,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;CACpC;AAUD,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;IAkChC;;;;;OAKG;YACW,YAAY;YAiBZ,WAAW;YAmDX,WAAW;IAmDzB;;;;OAIG;YACW,UAAU;YAkBV,cAAc;YAmBd,cAAc;YAiBd,gBAAgB;CAyB/B"}
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"}