@cejel/cejel 0.4.7 → 0.4.9

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 CHANGED
@@ -20,12 +20,8 @@ portable, offline trust certificate that aggregates them. Pipe in SARIF-compatib
20
20
  (MunaTrust, Snyk, Semgrep, CodeQL, Codex) plus OpenSSF Scorecard, and get one shareable
21
21
  certificate + badge over all of them. See "Aggregate your scanners" below.
22
22
 
23
- > Dogfooded in production. Cejel is run continuously on Barg Labs' own multi-product
24
- > monorepo — the ten-product studio it was built inside — which it currently scores
25
- > 3.3/4.0 on its rubric-native certificate. That transparency snapshot opts into prospective
26
- > v18; the public CLI default remains calibrated v17. On the comparative board, our code sits
27
- > outside the ranked population and receives no verdict band. We score ourselves before
28
- > asking you to score yourself.
23
+ > Cejel is used on Barg Labs’ own code. The [public board](https://cejel.dev/leaderboard/)
24
+ > labels publisher-owned snapshots separately from the ranked public repositories.
29
25
 
30
26
  ### Rubric calibration policy
31
27
 
@@ -93,7 +89,7 @@ if (-not $expected -or $actual -ne $expected.ToLowerInvariant()) {
93
89
  ```
94
90
 
95
91
  > **Windows signing status:** `cejel-Windows-x86_64.exe` is intentionally unsigned in
96
- > 0.4.7 and may trigger Microsoft SmartScreen. The release build removes Node's inherited
92
+ > 0.4.9 and may trigger Microsoft SmartScreen. The release build removes Node's inherited
97
93
  > signature before SEA injection and fails unless Windows reports the result as `NotSigned`;
98
94
  > it does not ship an invalid signature. Before running it, verify `SHA256SUMS` and the
99
95
  > GitHub build-provenance attestation. Each binary also has an attached SPDX SBOM and an
@@ -116,7 +112,7 @@ docker run --rm --network=none -v "$PWD:/w" -w /w -v "$PWD/cejel:/cejel:ro" debi
116
112
  npx @cejel/cejel@latest .
117
113
  ```
118
114
 
119
- > **Distribution note:** Cejel `0.4.7` is the coordinated release version for npm,
115
+ > **Distribution note:** Cejel `0.4.9` is the coordinated release version for npm,
120
116
  > standalone binaries, Docker/OCI, GitHub Action, Homebrew, and MCP Registry.
121
117
 
122
118
  `npx` can reuse a stale cached package. Force the current npm release with the `@latest`
@@ -178,16 +174,16 @@ gh attestation verify ./cejel-Windows-x86_64.exe -R BargLabs/cejel
178
174
  This is cryptographically signed provenance. It is distinct from Apple Developer ID or
179
175
  Microsoft Authenticode code-signing.
180
176
 
181
- **Docker / OCI.** The current container release is `0.4.7`:
177
+ **Docker / OCI.** The current container release is `0.4.9`:
182
178
 
183
179
  ```bash
184
- docker run --rm -i -v "$PWD:/workspace:ro" ghcr.io/barglabs/cejel:0.4.7
180
+ docker run --rm -i -v "$PWD:/workspace:ro" ghcr.io/barglabs/cejel:0.4.9
185
181
  ```
186
182
 
187
183
  The image defaults to `cejel-mcp` over stdio. To use the CLI instead:
188
184
 
189
185
  ```bash
190
- docker run --rm -v "$PWD:/workspace:ro" --entrypoint cejel ghcr.io/barglabs/cejel:0.4.7 .
186
+ docker run --rm -v "$PWD:/workspace:ro" --entrypoint cejel ghcr.io/barglabs/cejel:0.4.9 .
191
187
  ```
192
188
 
193
189
  The OCI image carries an SBOM, maximum-mode build provenance, and a signed registry
@@ -195,17 +191,15 @@ attestation.
195
191
 
196
192
  ## Leaderboard
197
193
 
198
- This repo ships the [Cejel OSS trust leaderboard](./leaderboard/leaderboard.md): elite OSS
199
- projects, the public Cejel repository itself, and one explicitly labeled transparency
200
- snapshot from the private studio monorepo where Cejel was built, with a per-repository
201
- evidence report for every row under [`leaderboard/reports/`](./leaderboard/reports/). The
202
- board is also hosted at [cejel.dev](https://cejel.dev). Every score is produced by the same
203
- sealed public scorer used by `npx @cejel/cejel@latest .`; no private domain collector contributes.
204
- For each public-repository row, check out the immutable source commit printed in its report
205
- and run the public scorer to reproduce the score, verdict, measured coverage, and evidence.
206
- The private Alfred snapshot discloses its limitation instead: its source commit and withheld
207
- locations are not publicly available, so that row is not independently reproducible and is
208
- not presented as a public-repository self-score.
194
+ The [Cejel OSS trust leaderboard](https://cejel.dev/leaderboard/) is hosted on cejel.dev,
195
+ which is the single current board. This repository no longer distributes a second copy of
196
+ its scores or certificates. The board records its producing package version, rubric,
197
+ run date, pinned public revisions, and reproduction instructions for that particular run.
198
+ The private Alfred transparency snapshot is not independently reproducible.
199
+
200
+ The site's History section preserves the **2026-08-18 withdrawal**: the earlier
201
+ sealed-public-scorer reproducibility claim was false. The stale prospective-rubric copy
202
+ previously linked here has been removed; it must not be treated as current evidence.
209
203
 
210
204
  ### Redaction policy
211
205
 
@@ -519,7 +513,7 @@ The OCI image is an alternative when Docker is the preferred execution boundary.
519
513
  the host path with the repository OpenClaw should allow Cejel to read:
520
514
 
521
515
  ```bash
522
- npx -y openclaw@latest mcp set cejel-oci '{"command":"docker","args":["run","--rm","-i","-v","/absolute/path/to/repo:/workspace:ro","ghcr.io/barglabs/cejel:0.4.7"]}'
516
+ npx -y openclaw@latest mcp set cejel-oci '{"command":"docker","args":["run","--rm","-i","-v","/absolute/path/to/repo:/workspace:ro","ghcr.io/barglabs/cejel:0.4.9"]}'
523
517
  npx -y openclaw@latest mcp doctor cejel-oci --probe
524
518
  ```
525
519
 
@@ -546,6 +540,47 @@ part of the scoring guarantee. If the tracked-file inventory fails unexpectedly,
546
540
  HTML, and markdown certificates declare that the scanner used its bounded directory fallback
547
541
  instead of silently presenting the two inventories as equivalent.
548
542
 
543
+ ## What a certificate's scope means
544
+
545
+ A certificate scores the repository tree at one pinned revision, and only that tree. That
546
+ boundary is deliberate: a certificate that reached outside the pinned tree could not be
547
+ reproduced by whoever receives it, and reproducibility is the entire product. Scoring only the
548
+ pinned tree is correct — the gap was that nothing on the certificate itself told a reader which
549
+ kind of statement they were holding. A repository whose regression suite lives in a separate
550
+ repository, checked out and run by its own CI, is correctly reported as having zero test files
551
+ against its source files. That statement is true about the tree and false about the system, and a
552
+ reader with no other context cannot tell the difference.
553
+
554
+ Every certificate now carries a standing scope line, in the "How to read this certificate"
555
+ section on every surface (HTML, Markdown, terminal), regardless of verdict: the certificate is a
556
+ statement about the repository tree at the pinned revision, not about the system that tree
557
+ belongs to, and evidence outside that tree is neither seen nor claimed to be absent. This is
558
+ additive, not a hedge — a finding that says evidence was not found in this tree stays exactly as
559
+ stated.
560
+
561
+ Four specific situations can make the tree's own conclusion misleading about the system it
562
+ belongs to:
563
+
564
+ - **A test suite kept in a separate repository.** Not detectable from inside the pinned tree —
565
+ there is no reliable signal that a sibling repository exists. Covered by the standing scope
566
+ line above, not a conditional disclosure.
567
+ - **CI configuration that changes into a different working directory before running its checks.**
568
+ Also not detectable without executing the CI job itself, which the offline scanner does not do.
569
+ Covered by the standing scope line above.
570
+ - **A large implementation file that exceeds the read limit.** This one is detectable, and
571
+ disclosed conditionally when it happens: when a file above the size ceiling is the reason a
572
+ specific signal has nothing to measure, the certificate's scan-limitations section names it —
573
+ "declined a large implementation file that exceeded the repository content size limit" — rather
574
+ than folding it into the generic coverage-limit sentence used for an extension exclusion or a
575
+ non-regular file. Today this fires for two A3 signals (health/readiness route detection and
576
+ observability-marker counting); it extends to more signals as they adopt the same per-signal
577
+ attribution.
578
+ - **A recognized-but-nonfunctional package script**, such as npm's auto-generated
579
+ `"test": "echo \"Error: no test specified\" && exit 1"` placeholder being credited the same as a
580
+ real test runner. This was a detector defect, not a scope-disclosure gap — Cejel now checks the
581
+ `test` script's content against known test-runner invocations rather than crediting it by key
582
+ presence alone, so no separate disclosure line is needed for it.
583
+
549
584
  ## Help validate Cejel
550
585
 
551
586
  Cejel does not collect telemetry. External validation is therefore opt-in and inspectable:
@@ -680,7 +715,7 @@ published in public.
680
715
 
681
716
  **No rubric change re-scores you silently.** Every change to scoring behavior requires a
682
717
  `WITAN_RUBRIC_VERSION` bump and a corpus-wide before/after delta published in
683
- [`docs/leaderboard/RUBRIC_CHANGELOG.md`](../../docs/leaderboard/RUBRIC_CHANGELOG.md) — score,
718
+ [`leaderboard/RUBRIC_CHANGELOG.md`](./leaderboard/RUBRIC_CHANGELOG.md) — score,
684
719
  verdict, and rank for every repository, "no repository moved" stated explicitly when that is
685
720
  the result. A build that changes scoring without both fails; see that file's `v2` entry for
686
721
  the home-field fix above as the first rubric change recorded this way.
@@ -5,20 +5,20 @@ import {
5
5
  deriveProductIdentity,
6
6
  runCejelScan,
7
7
  serializeWitanReport
8
- } from "../chunk-QTLLASOO.js";
8
+ } from "../chunk-TUUNJP27.js";
9
9
  import {
10
10
  listCejelLlmPackFiles
11
- } from "../chunk-EP7YYWEP.js";
12
- import "../chunk-OIGCYULH.js";
11
+ } from "../chunk-IN2LPGGU.js";
12
+ import "../chunk-IHT7B6L7.js";
13
13
  import {
14
14
  external_exports
15
- } from "../chunk-UYJBSQCV.js";
15
+ } from "../chunk-GKYTLWQK.js";
16
16
  import {
17
17
  init_esm_shims,
18
18
  readRepoText,
19
19
  recordContentSkip,
20
20
  recordFilesystemSkip
21
- } from "../chunk-ZNVILRHK.js";
21
+ } from "../chunk-PTZU6G4E.js";
22
22
 
23
23
  // src/calibration/llm-detector.ts
24
24
  init_esm_shims();
@@ -4,7 +4,7 @@ const require = __cejelCreateRequire(import.meta.url);
4
4
  import {
5
5
  __export,
6
6
  init_esm_shims
7
- } from "./chunk-ZNVILRHK.js";
7
+ } from "./chunk-PTZU6G4E.js";
8
8
 
9
9
  // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/external.js
10
10
  var external_exports = {};
@@ -3,7 +3,7 @@ import { createRequire as __cejelCreateRequire } from 'node:module';
3
3
  const require = __cejelCreateRequire(import.meta.url);
4
4
  import {
5
5
  init_esm_shims
6
- } from "./chunk-ZNVILRHK.js";
6
+ } from "./chunk-PTZU6G4E.js";
7
7
 
8
8
  // src/witan/git-exec.ts
9
9
  init_esm_shims();
@@ -5,10 +5,10 @@ import {
5
5
  describeGitFailure,
6
6
  execGit,
7
7
  isExpectedGitAbsence
8
- } from "./chunk-OIGCYULH.js";
8
+ } from "./chunk-IHT7B6L7.js";
9
9
  import {
10
10
  init_esm_shims
11
- } from "./chunk-ZNVILRHK.js";
11
+ } from "./chunk-PTZU6G4E.js";
12
12
 
13
13
  // src/packs/llm/files.ts
14
14
  init_esm_shims();
@@ -7,7 +7,7 @@ import {
7
7
  __filename,
8
8
  __require,
9
9
  init_esm_shims
10
- } from "./chunk-ZNVILRHK.js";
10
+ } from "./chunk-PTZU6G4E.js";
11
11
 
12
12
  // node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/typescript.js
13
13
  var require_typescript = __commonJS({
@@ -62,28 +62,58 @@ var MAX_REPOSITORY_CONTENT_BYTES = 512e3;
62
62
  init_esm_shims();
63
63
  import { closeSync, lstatSync, openSync, readFileSync, readSync } from "fs";
64
64
  import { resolve } from "path";
65
+ var READ_FAILURE_REASONS = /* @__PURE__ */ new Set(["unreadable", "denied_path"]);
66
+ function isReadFailureReason(reason) {
67
+ return READ_FAILURE_REASONS.has(reason);
68
+ }
69
+ function classifyAbstentionReason(reasons) {
70
+ if (!reasons || reasons.size === 0) return {};
71
+ for (const reason of reasons) {
72
+ if (isReadFailureReason(reason)) return {};
73
+ }
74
+ const priority = [
75
+ "too_large",
76
+ "excluded_by_extension",
77
+ "non_regular_file"
78
+ ];
79
+ const chosen = priority.find((reason) => reasons.has(reason));
80
+ return chosen ? { insufficientDataReason: chosen } : {};
81
+ }
65
82
  function contentReadSignalKey(criterionId, signalId) {
66
83
  return [criterionId, signalId].join(":");
67
84
  }
68
85
  var activeSession;
86
+ function addSkipReason(map, key, reason) {
87
+ const existing = map.get(key);
88
+ if (existing) {
89
+ existing.add(reason);
90
+ } else {
91
+ map.set(key, /* @__PURE__ */ new Set([reason]));
92
+ }
93
+ }
69
94
  function errnoClass(error) {
70
95
  if (typeof error !== "object" || error === null || !("code" in error)) return null;
71
96
  const code = error.code;
72
97
  return typeof code === "string" && /^E[A-Z0-9_]+$/.test(code) ? code : null;
73
98
  }
99
+ function attributeSkip(session, criterion, signals, reason) {
100
+ session.affectedCriteria.add(criterion);
101
+ if (signals && signals.length > 0) {
102
+ for (const signal of signals) {
103
+ const key = contentReadSignalKey(criterion, signal);
104
+ session.affectedSignals.add(key);
105
+ addSkipReason(session.signalSkipReasons, key, reason);
106
+ }
107
+ } else {
108
+ session.unattributedCriteria.add(criterion);
109
+ addSkipReason(session.criterionSkipReasons, criterion, reason);
110
+ }
111
+ }
74
112
  function recordSkip(path2, reason, errno, affectsCurrentCriterion = false, deduplicate = false) {
75
113
  const session = activeSession;
76
114
  if (!session) return;
77
115
  if (affectsCurrentCriterion && session.criterion) {
78
- session.affectedCriteria.add(session.criterion);
79
- const signals = session.signals;
80
- if (signals && signals.length > 0) {
81
- for (const signal of signals) {
82
- session.affectedSignals.add(contentReadSignalKey(session.criterion, signal));
83
- }
84
- } else {
85
- session.unattributedCriteria.add(session.criterion);
86
- }
116
+ attributeSkip(session, session.criterion, session.signals, reason);
87
117
  }
88
118
  if (deduplicate) {
89
119
  const key = `${resolve(path2)}\0${reason}\0${errno ?? ""}`;
@@ -121,7 +151,9 @@ function trackContentReads(_repoPath, collect) {
121
151
  summary: summaryFor(existing),
122
152
  affectedCriteria: existing.affectedCriteria,
123
153
  affectedSignals: existing.affectedSignals,
124
- unattributedCriteria: existing.unattributedCriteria
154
+ unattributedCriteria: existing.unattributedCriteria,
155
+ criterionSkipReasons: existing.criterionSkipReasons,
156
+ signalSkipReasons: existing.signalSkipReasons
125
157
  };
126
158
  }
127
159
  const session = {
@@ -136,7 +168,10 @@ function trackContentReads(_repoPath, collect) {
136
168
  deduplicatedSkips: /* @__PURE__ */ new Set(),
137
169
  affectedCriteria: /* @__PURE__ */ new Set(),
138
170
  affectedSignals: /* @__PURE__ */ new Set(),
139
- unattributedCriteria: /* @__PURE__ */ new Set()
171
+ unattributedCriteria: /* @__PURE__ */ new Set(),
172
+ criterionSkipReasons: /* @__PURE__ */ new Map(),
173
+ signalSkipReasons: /* @__PURE__ */ new Map(),
174
+ withheldPaths: /* @__PURE__ */ new Map()
140
175
  };
141
176
  activeSession = session;
142
177
  try {
@@ -146,7 +181,9 @@ function trackContentReads(_repoPath, collect) {
146
181
  summary: summaryFor(session),
147
182
  affectedCriteria: session.affectedCriteria,
148
183
  affectedSignals: session.affectedSignals,
149
- unattributedCriteria: session.unattributedCriteria
184
+ unattributedCriteria: session.unattributedCriteria,
185
+ criterionSkipReasons: session.criterionSkipReasons,
186
+ signalSkipReasons: session.signalSkipReasons
150
187
  };
151
188
  } finally {
152
189
  activeSession = void 0;
@@ -183,15 +220,21 @@ function withContentReadSignals(criterionId, signalIds, collect) {
183
220
  function recordContentSkip(path2, reason, deduplicate = false) {
184
221
  recordSkip(path2, reason, void 0, false, deduplicate);
185
222
  }
186
- function recordContentSkipForCriteria(path2, reason, criteria, deduplicate = false) {
223
+ function registerWithheldRepoPath(relativePath, reason) {
187
224
  const session = activeSession;
188
- if (session) {
189
- for (const criterion of criteria) {
190
- session.affectedCriteria.add(criterion);
191
- session.unattributedCriteria.add(criterion);
192
- }
225
+ if (!session) return;
226
+ addSkipReason(session.withheldPaths, relativePath, reason);
227
+ }
228
+ function abstainSignalOnWithheldPaths(criterionId, signalId, wouldHaveRead) {
229
+ const session = activeSession;
230
+ if (!session) return false;
231
+ let abstained = false;
232
+ for (const [path2, reasons] of session.withheldPaths) {
233
+ if (!wouldHaveRead(path2)) continue;
234
+ abstained = true;
235
+ for (const reason of reasons) attributeSkip(session, criterionId, [signalId], reason);
193
236
  }
194
- recordSkip(path2, reason, void 0, false, deduplicate);
237
+ return abstained;
195
238
  }
196
239
  function recordFilesystemSkip(path2, error, deniedContext = false, deduplicate = true) {
197
240
  const errno = errnoClass(error);
@@ -264,13 +307,15 @@ export {
264
307
  __filename,
265
308
  init_esm_shims,
266
309
  MAX_REPOSITORY_CONTENT_BYTES,
310
+ classifyAbstentionReason,
267
311
  contentReadSignalKey,
268
312
  trackContentReads,
269
313
  withContentReadCriterion,
270
314
  withContentReadSignal,
271
315
  withContentReadSignals,
272
316
  recordContentSkip,
273
- recordContentSkipForCriteria,
317
+ registerWithheldRepoPath,
318
+ abstainSignalOnWithheldPaths,
274
319
  recordFilesystemSkip,
275
320
  readRepoText,
276
321
  readRepoTextPrefix