@smartergpt/lexrunner 1.4.0 → 1.5.1
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/CHANGELOG.md +116 -0
- package/README.md +29 -23
- package/dist/{audit-5ZUBPZZX.js → audit-SKMMC2U4.js} +1 -1
- package/dist/{autopilot-JXO4MZ6H.js → autopilot-62Y2M2ZO.js} +1 -1
- package/dist/{chunk-R4DWK6FE.js → chunk-6PZDSWCG.js} +13 -10
- package/dist/{chunk-WFN4JTZI.js → chunk-LQSRQ6Z3.js} +5 -5
- package/dist/{chunk-WSJEPY7T.js → chunk-TIMHM7VL.js} +386 -80
- package/dist/cli.cjs +15467 -2652
- package/dist/cli.d.ts +1279 -10
- package/dist/cli.js +14699 -2226
- package/dist/{constraints-V4VWCWR5.js → constraints-2ZK5FJFA.js} +1 -1
- package/package.json +3 -2
- package/schemas/gate-execution-receipt.schema.json +161 -0
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,122 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [1.5.1] - 2026-08-23
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- **Credential-free release ancestry verification** - Verify that the signed release commit is
|
|
14
|
+
contained in `main` through the authenticated GitHub compare API after checkout credentials are
|
|
15
|
+
deliberately discarded. This recovery release carries forward the complete 1.5.0 feature set;
|
|
16
|
+
the immutable `lexrunner-v1.5.0` workflow failed closed before install or publication.
|
|
17
|
+
|
|
18
|
+
## [1.5.0] - 2026-08-23
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- **Durable Attempt awaitables** - Add bounded lifecycle observation and wakeup contracts that bind
|
|
23
|
+
the exact Attempt revision and terminal state without embedding credentials or accepting unsafe
|
|
24
|
+
replay state.
|
|
25
|
+
- **Executable gate receipts** - Retain fresh per-attempt command evidence with exact cwd,
|
|
26
|
+
shell/argv identity, duration, exit and failure classification, bounded stream hashes, and
|
|
27
|
+
declared artifact hashes.
|
|
28
|
+
- **Disposable workspace recovery controller** - Add a root-owned WSL2 controller that prepares
|
|
29
|
+
bounded Attempt-owned ext4 roots from a hash-checked sealed source, records pre-mutation
|
|
30
|
+
filesystem and Git identities, journals each root before exposing it, and atomically detaches and
|
|
31
|
+
discards only the exactly bound root. Recovery is resumable across preparation, detach, evidence,
|
|
32
|
+
and delete crash windows. Complete bounded pre/post manifests and canonical deltas remain
|
|
33
|
+
resolvable from controller-only evidence after deletion, while strict receipts bind their hashes,
|
|
34
|
+
worker absence, recovery authorization, and workspace absence without creating a writer grant or
|
|
35
|
+
launch path.
|
|
36
|
+
- **Governed workspace mutation profile** - Add a non-review task profile whose proposed authority
|
|
37
|
+
is limited to an Attempt-owned read scope and exact writable-path-set hash with whole-workspace
|
|
38
|
+
discard recovery. The profile exports no execution-binding constructor: schema records and an
|
|
39
|
+
adapter manifest cannot mint a write receipt. Protected authority integration must independently
|
|
40
|
+
resolve exact-image qualification and controller-prepared workspace evidence by hash, validate
|
|
41
|
+
freshness with its own trusted clock, and construct the generic grant only after those records
|
|
42
|
+
reconstruct the prompt, source, read, write, ownership, and rollback bindings. The task input
|
|
43
|
+
hash also binds its normalized duration, output-byte, evidence-byte, and tool-call budgets.
|
|
44
|
+
- **Governed task capability foundation** - Add a review-neutral task/profile binding and positive
|
|
45
|
+
capability ceiling that represents recoverable workspace writes, explicitly bounded external
|
|
46
|
+
effects, contained runtime execution, and attenuated nested Delegations without weakening `NO`.
|
|
47
|
+
- **Governed committed-corpus review** - Bind a clean committed native-WSL candidate to its exact
|
|
48
|
+
Attempt, workspace lease, task packet, launch envelope, and path mapping; export only bounded Git
|
|
49
|
+
object bytes and the exact patch; seal them read-only for the asynchronous two-phase Codex review.
|
|
50
|
+
- **Independent repository verification** - Reopen the authoritative lifecycle records and require
|
|
51
|
+
protected provider receipts to match the corpus, prompt, schema, task offer, and Delegation before
|
|
52
|
+
a review can become admissible.
|
|
53
|
+
|
|
54
|
+
### Changed
|
|
55
|
+
|
|
56
|
+
- **Native Windows gate execution** - Run local command gates through a resolved PowerShell runtime
|
|
57
|
+
with explicit argument and working-directory identity instead of accidentally crossing into WSL
|
|
58
|
+
or relying on a platform shell shim.
|
|
59
|
+
- **Provider stream failure terminality** - Convert bounded-line, invalid-event, sequence, and
|
|
60
|
+
transport failures into a durable `failed` executor event with a bounded protected failure frame;
|
|
61
|
+
cancel the provider, never retain raw failure output in lifecycle state, and reserve `lost` for
|
|
62
|
+
unexplained stream disappearance.
|
|
63
|
+
- **Governed review task profile** - Express read-only review through a durable generic
|
|
64
|
+
`GovernedTaskSpec`, bind the Delegation offer to its exact task and provider, and independently
|
|
65
|
+
reconstruct the profile from protected prompt, corpus, output-contract, and budget bindings;
|
|
66
|
+
release accepted work only after the generic grant and qualified adapter evaluate, and dispatch
|
|
67
|
+
`PASS`/`BLOCK` interpretation through the exact profile verifier.
|
|
68
|
+
- **Qualified provider topology** - Bind the root-owned repository exporter and exact Git executable
|
|
69
|
+
and version into live qualification evidence, and securely discard sealed corpora that never
|
|
70
|
+
become operation-bound.
|
|
71
|
+
|
|
72
|
+
### Fixed
|
|
73
|
+
|
|
74
|
+
- **Gate artifact freshness** - Fail closed when declared evidence is missing, stale, unsupported,
|
|
75
|
+
changed during retention, or cannot be preserved with identical bytes.
|
|
76
|
+
- **Cross-platform package smoke** - Invoke npm and installed package bin targets through the active
|
|
77
|
+
Node runtime so packed-consumer validation works on Windows without spawning `.cmd` shims.
|
|
78
|
+
- **Windows Git-backed verification** - Render prompt-search diagnostics with stable separators,
|
|
79
|
+
use privilege-free junction fixtures, and bound process-restart tests with Windows-sized timing
|
|
80
|
+
and cleanup retries.
|
|
81
|
+
- **Governed refusal and budget enforcement** - Persist an offer-phase `NO` directly from the
|
|
82
|
+
offered Delegation state, and independently reject duration, output, evidence-byte, or tool-call
|
|
83
|
+
usage beyond the exact task budget bound to execution requirements and the evidence reservation.
|
|
84
|
+
- **Generic continuation and outcome isolation** - Deny both direct work and post-`ACCEPT`
|
|
85
|
+
continuation when the durable generic task/execution binding is absent, keep unbound legacy
|
|
86
|
+
offers refusal-only, reject contradictory `PASS` output with blocking findings, and make generic
|
|
87
|
+
results and verification receipts accept profile-owned outcome identifiers without embedding the
|
|
88
|
+
code-review vocabulary. Bind the root task grant issuer to the operator principal named by the
|
|
89
|
+
protected authorization requirements so a self-consistent caller grant cannot mint authority.
|
|
90
|
+
- **Git object substitution defense** - Verify every exported file against the blob object ID in
|
|
91
|
+
the candidate tree, preserve that object ID in the sealed manifest, and recheck the binding at
|
|
92
|
+
both the Windows corpus parser and provider boundary.
|
|
93
|
+
- **Qualification upgrade boundary** - Reject pre-profile qualification manifests so repository
|
|
94
|
+
review cannot use a legacy attestation that omits the exporter and Git executable hashes.
|
|
95
|
+
- **Repository launch lease race** - Atomically require the bound active workspace lease when
|
|
96
|
+
authorizing the offer, creating the durable operation, and authorizing post-acceptance work; the
|
|
97
|
+
independent verifier also rejects results after lease release.
|
|
98
|
+
- **Repository corpus memory bounds** - Read Git blobs one at a time, reject aggregate tree size from
|
|
99
|
+
object headers before buffering payloads, and stop every Git metadata or patch stream after its
|
|
100
|
+
declared maximum plus one byte.
|
|
101
|
+
- **Repository receipt lifecycle projection** - Verify the provider's corpus-header receipt against
|
|
102
|
+
provider-visible fields while independently enforcing the host-owned workspace-lease revision.
|
|
103
|
+
- **Failed repository launch cleanup** - Treat post-validation launch construction transactionally:
|
|
104
|
+
stop partially created worker units and remove partial spools and unreferenced sealed corpora
|
|
105
|
+
whenever launch fails before returning a handle.
|
|
106
|
+
|
|
107
|
+
## [1.4.1] - 2026-08-04
|
|
108
|
+
|
|
109
|
+
### Added
|
|
110
|
+
|
|
111
|
+
- **Canonical CLI executable** - Publish `lexrunner` as the primary npm binary alongside
|
|
112
|
+
`lexrunner-mcp` and the retained `lex-pr` compatibility alias.
|
|
113
|
+
|
|
114
|
+
### Changed
|
|
115
|
+
|
|
116
|
+
- **Consistent CLI identity** - Use `lexrunner` in root and subcommand help, completions, diagnostic
|
|
117
|
+
prefixes, installation guidance, current release documentation, and generated CLI/MCP surface
|
|
118
|
+
guidance.
|
|
119
|
+
|
|
120
|
+
### Fixed
|
|
121
|
+
|
|
122
|
+
- **Package/executable mismatch** - Ensure installing `@smartergpt/lexrunner` exposes an executable
|
|
123
|
+
matching the package and product name without breaking existing `lex-pr` automation.
|
|
124
|
+
|
|
9
125
|
## [1.4.0] - 2026-08-04
|
|
10
126
|
|
|
11
127
|
### Added
|
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# LexRunner (`
|
|
1
|
+
# LexRunner (`lexrunner`)
|
|
2
2
|
|
|
3
3
|
LexRunner turns a changing set of pull requests into a reviewable integration program: discover
|
|
4
4
|
the work, freeze a dependency plan, run bounded gates, preserve evidence, and merge only with
|
|
@@ -19,13 +19,13 @@ branch, pushing, opening a PR, or merging requires separate approval.
|
|
|
19
19
|
|
|
20
20
|
LexRunner’s supported workflow has grown in layers. A normal user can stop at any layer.
|
|
21
21
|
|
|
22
|
-
| Layer | Current capability | First surface
|
|
23
|
-
| ------------------- | ------------------------------------------------------------------------------------------------------------ |
|
|
24
|
-
| Deterministic plan | Freeze PRs and declared dependencies into schema-versioned `plan.json` | `
|
|
25
|
-
| Merge-weave | Compute merge order, preview integration, run gates, and apply authorized merges | `
|
|
26
|
-
| Run and evidence | Persist bounded receipts, independent verification, acceptance, and artifacts | `
|
|
27
|
-
| Fanout | Harvest and analyze issue/PR evidence for parallel work planning | `
|
|
28
|
-
| Assisted agent work | Prepare an immutable packet and workspace envelope, attach a foreground-owned worker, then verify its claims | CLI/MCP Attempt lifecycle
|
|
22
|
+
| Layer | Current capability | First surface |
|
|
23
|
+
| ------------------- | ------------------------------------------------------------------------------------------------------------ | ----------------------------------------- |
|
|
24
|
+
| Deterministic plan | Freeze PRs and declared dependencies into schema-versioned `plan.json` | `lexrunner weave plan` |
|
|
25
|
+
| Merge-weave | Compute merge order, preview integration, run gates, and apply authorized merges | `lexrunner weave *`, `lexrunner gate run` |
|
|
26
|
+
| Run and evidence | Persist bounded receipts, independent verification, acceptance, and artifacts | `lexrunner attempt *` |
|
|
27
|
+
| Fanout | Harvest and analyze issue/PR evidence for parallel work planning | `lexrunner fanout *` |
|
|
28
|
+
| Assisted agent work | Prepare an immutable packet and workspace envelope, attach a foreground-owned worker, then verify its claims | CLI/MCP Attempt lifecycle |
|
|
29
29
|
|
|
30
30
|
The ADR-010 coordination model is accepted and its assisted Attempt lifecycle is implemented.
|
|
31
31
|
LexRunner also has a tested headless reconciliation **application boundary**, but it is not a
|
|
@@ -39,21 +39,21 @@ remain unproven. See [ADR-010](docs/adr/ADR-010-agent-work-orchestration-protoco
|
|
|
39
39
|
First inspect without mutation:
|
|
40
40
|
|
|
41
41
|
```bash
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
lexrunner --version
|
|
43
|
+
lexrunner workspace doctor --json
|
|
44
|
+
lexrunner weave discover --json
|
|
45
45
|
```
|
|
46
46
|
|
|
47
47
|
After approving a local, reversible artifact, freeze and inspect a plan:
|
|
48
48
|
|
|
49
49
|
```bash
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
lexrunner weave plan --from-github --output plan.json --json
|
|
51
|
+
lexrunner schema validate plan.json --json
|
|
52
|
+
lexrunner weave merge-order plan.json --json
|
|
53
|
+
lexrunner gate run plan.json --dry-run --json
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
-
These commands do not merge. `
|
|
56
|
+
These commands do not merge. `lexrunner weave apply --execute` is a separate mutation and should be
|
|
57
57
|
run only after reviewing the frozen plan, authority, gates, and target branch.
|
|
58
58
|
|
|
59
59
|
For a guided merge-weave walkthrough, use
|
|
@@ -94,28 +94,34 @@ organization, so a human with organization access must authenticate the npm CLI
|
|
|
94
94
|
```bash
|
|
95
95
|
npm login --scope=@smartergpt --registry=https://registry.npmjs.org/
|
|
96
96
|
npm install --save-dev @smartergpt/lexrunner
|
|
97
|
-
npx
|
|
97
|
+
npx lexrunner --version
|
|
98
98
|
```
|
|
99
99
|
|
|
100
100
|
Global installation is also supported:
|
|
101
101
|
|
|
102
102
|
```bash
|
|
103
103
|
npm install --global @smartergpt/lexrunner
|
|
104
|
-
|
|
104
|
+
lexrunner --version
|
|
105
105
|
```
|
|
106
106
|
|
|
107
107
|
Do not place npm tokens in the repository or a chat transcript. Windows/private-package validation
|
|
108
108
|
is documented in the [Node 24 migration guide](docs/node-24-migration.md).
|
|
109
109
|
|
|
110
|
-
|
|
110
|
+
`lexrunner` is the canonical CLI name. The existing `lex-pr` executable remains an additive
|
|
111
|
+
compatibility alias and invokes the same program, so existing automation does not need to change.
|
|
112
|
+
|
|
113
|
+
The checked-in package version is the single source for `lexrunner --version` and
|
|
114
|
+
`lex-pr --version`.
|
|
111
115
|
|
|
112
116
|
<!-- BEGIN GENERATED PACKAGE VERSION -->
|
|
113
117
|
|
|
114
|
-
Current repository package version: **1.
|
|
118
|
+
Current repository package version: **1.5.1**. npm availability and dist-tags are separate
|
|
115
119
|
release evidence; inspect the registry rather than inferring publication from source metadata.
|
|
116
120
|
<!-- END GENERATED PACKAGE VERSION -->
|
|
117
121
|
|
|
118
|
-
See the [1.
|
|
122
|
+
See the [1.5.1 release notes](docs/releases/1.5.1.md), the
|
|
123
|
+
[1.4.1 canonical CLI release](docs/releases/1.4.1.md), the
|
|
124
|
+
[1.4.0 native-host boundary release](docs/releases/1.4.0.md), the
|
|
119
125
|
[1.3.0 dogfood release](docs/releases/1.3.0.md), the
|
|
120
126
|
[1.2.1 publication repair](docs/releases/1.2.1.md), and the underlying
|
|
121
127
|
[1.2.0 compatibility decision](docs/releases/1.2.0.md) for package disposition, semver rationale,
|
|
@@ -172,7 +178,7 @@ For implementation work, use the touched/adjacent gate selector and let CI prove
|
|
|
172
178
|
high-risk changes:
|
|
173
179
|
|
|
174
180
|
```bash
|
|
175
|
-
|
|
181
|
+
lexrunner gate select --base <base-sha> --head <head-sha> --json
|
|
176
182
|
```
|
|
177
183
|
|
|
178
184
|
Release validation remains exhaustive. See [`AGENTS.md`](AGENTS.md),
|
|
@@ -182,7 +188,7 @@ Release validation remains exhaustive. See [`AGENTS.md`](AGENTS.md),
|
|
|
182
188
|
## Package and licensing
|
|
183
189
|
|
|
184
190
|
- Package: `@smartergpt/lexrunner`
|
|
185
|
-
- CLI: `lex-pr`
|
|
191
|
+
- CLI: `lexrunner` (`lex-pr` compatibility alias)
|
|
186
192
|
- MCP bin: `lexrunner-mcp`
|
|
187
193
|
- Runtime dependency: `@smartergpt/lex` (MIT)
|
|
188
194
|
- LexRunner license: SmarterGPT Source-Available Personal Use License
|
|
@@ -514,7 +514,7 @@ var AuditEmitter = class {
|
|
|
514
514
|
const auditContext = await collectContext(contextTypes);
|
|
515
515
|
this.context = auditContext;
|
|
516
516
|
} catch (err) {
|
|
517
|
-
console.warn("[
|
|
517
|
+
console.warn("[lexrunner] audit: context collection failed", err);
|
|
518
518
|
this.context = {};
|
|
519
519
|
}
|
|
520
520
|
} else {
|
|
@@ -534,7 +534,7 @@ var AuditEmitter = class {
|
|
|
534
534
|
}
|
|
535
535
|
this.ndjsonStream = fs3.createWriteStream(this.ndjsonPath, { flags: "a", autoClose: true });
|
|
536
536
|
this.ndjsonStream.on("error", (err) => {
|
|
537
|
-
console.warn("[
|
|
537
|
+
console.warn("[lexrunner] audit: ndjson stream error (ignored)", String(err));
|
|
538
538
|
});
|
|
539
539
|
const schemaPath = path3.join(this.auditDir, "audit.schema.json");
|
|
540
540
|
const schema = {
|
|
@@ -627,7 +627,7 @@ var AuditEmitter = class {
|
|
|
627
627
|
this.ndjsonStream.write(line);
|
|
628
628
|
}
|
|
629
629
|
} catch (e) {
|
|
630
|
-
console.warn("[
|
|
630
|
+
console.warn("[lexrunner] audit: ndjson write failed (ignored)", String(e));
|
|
631
631
|
}
|
|
632
632
|
this.eventCount++;
|
|
633
633
|
this.eventsByType[event] = (this.eventsByType[event] || 0) + 1;
|
|
@@ -652,7 +652,7 @@ var AuditEmitter = class {
|
|
|
652
652
|
try {
|
|
653
653
|
await this.ingestSidecar();
|
|
654
654
|
} catch (e) {
|
|
655
|
-
console.warn("[
|
|
655
|
+
console.warn("[lexrunner] audit: sidecar ingestion error (ignored)", String(e));
|
|
656
656
|
}
|
|
657
657
|
}, 5e3);
|
|
658
658
|
try {
|
|
@@ -689,11 +689,14 @@ var AuditEmitter = class {
|
|
|
689
689
|
this.eventsByType[event.event] = (this.eventsByType[event.event] || 0) + 1;
|
|
690
690
|
}
|
|
691
691
|
} catch (innerErr) {
|
|
692
|
-
console.warn(
|
|
692
|
+
console.warn(
|
|
693
|
+
"[lexrunner] audit: error ingesting sidecar event (ignored)",
|
|
694
|
+
String(innerErr)
|
|
695
|
+
);
|
|
693
696
|
}
|
|
694
697
|
});
|
|
695
698
|
} catch (err) {
|
|
696
|
-
console.warn("[
|
|
699
|
+
console.warn("[lexrunner] audit: ingestSidecarFiles failed (ignored)", String(err));
|
|
697
700
|
}
|
|
698
701
|
}
|
|
699
702
|
/**
|
|
@@ -862,11 +865,11 @@ var AuditEmitter = class {
|
|
|
862
865
|
else if (status === "blocked") totalBlocked++;
|
|
863
866
|
}
|
|
864
867
|
} catch (parseError) {
|
|
865
|
-
console.warn("[
|
|
868
|
+
console.warn("[lexrunner] audit: skipping malformed line in audit.ndjson");
|
|
866
869
|
}
|
|
867
870
|
}
|
|
868
871
|
} catch (e) {
|
|
869
|
-
console.warn("[
|
|
872
|
+
console.warn("[lexrunner] audit: failed to read audit.ndjson (ignored)", String(e));
|
|
870
873
|
return;
|
|
871
874
|
}
|
|
872
875
|
const gateMatrix = {
|
|
@@ -909,11 +912,11 @@ var AuditEmitter = class {
|
|
|
909
912
|
vulnEvents.push(event);
|
|
910
913
|
}
|
|
911
914
|
} catch (parseError) {
|
|
912
|
-
console.warn("[
|
|
915
|
+
console.warn("[lexrunner] audit: skipping malformed line in audit.ndjson");
|
|
913
916
|
}
|
|
914
917
|
}
|
|
915
918
|
} catch (e) {
|
|
916
|
-
console.warn("[
|
|
919
|
+
console.warn("[lexrunner] audit: failed to read audit.ndjson for SARIF (ignored)", String(e));
|
|
917
920
|
return;
|
|
918
921
|
}
|
|
919
922
|
if (vulnEvents.length === 0) {
|
|
@@ -213,18 +213,18 @@ function readGovernanceLogs() {
|
|
|
213
213
|
const [major] = rawLog.schemaVersion.split(".").map(Number);
|
|
214
214
|
if (major > CURRENT_MAJOR_VERSION) {
|
|
215
215
|
console.warn(
|
|
216
|
-
`[
|
|
216
|
+
`[lexrunner] Skipping log ${file}: schema v${rawLog.schemaVersion} not supported (current: v${CURRENT_MAJOR_VERSION}.x.x)`
|
|
217
217
|
);
|
|
218
218
|
continue;
|
|
219
219
|
}
|
|
220
220
|
} else {
|
|
221
|
-
console.warn(`[
|
|
221
|
+
console.warn(`[lexrunner] Skipping log ${file}: missing schemaVersion (legacy format)`);
|
|
222
222
|
continue;
|
|
223
223
|
}
|
|
224
224
|
const parsed = GovernanceComparisonLogSchema.parse(rawLog);
|
|
225
225
|
logs.push(parsed);
|
|
226
226
|
} catch (error) {
|
|
227
|
-
console.warn(`[
|
|
227
|
+
console.warn(`[lexrunner] Skipping invalid log ${file}:`, error);
|
|
228
228
|
}
|
|
229
229
|
}
|
|
230
230
|
logs.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
|
|
@@ -248,7 +248,7 @@ function readGovernanceLogsWithLegacy() {
|
|
|
248
248
|
const [major] = rawLog.schemaVersion.split(".").map(Number);
|
|
249
249
|
if (major > CURRENT_MAJOR_VERSION) {
|
|
250
250
|
console.warn(
|
|
251
|
-
`[
|
|
251
|
+
`[lexrunner] Skipping log ${file}: schema v${rawLog.schemaVersion} not supported (current: v${CURRENT_MAJOR_VERSION}.x.x)`
|
|
252
252
|
);
|
|
253
253
|
continue;
|
|
254
254
|
}
|
|
@@ -291,7 +291,7 @@ function readGovernanceLogsWithLegacy() {
|
|
|
291
291
|
normalizationWarnings: warnings
|
|
292
292
|
});
|
|
293
293
|
} catch (error) {
|
|
294
|
-
console.warn(`[
|
|
294
|
+
console.warn(`[lexrunner] Skipping invalid log ${file} (even with normalization):`, error);
|
|
295
295
|
}
|
|
296
296
|
}
|
|
297
297
|
results.sort((a, b) => new Date(b.log.timestamp).getTime() - new Date(a.log.timestamp).getTime());
|