@cejel/cejel 0.6.3 → 0.6.4

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
@@ -92,7 +92,7 @@ if (-not $expected -or $actual -ne $expected.ToLowerInvariant()) {
92
92
  ```
93
93
 
94
94
  > **Windows signing status:** `cejel-Windows-x86_64.exe` is intentionally unsigned in
95
- > 0.6.3 and may trigger Microsoft SmartScreen. The release build removes Node's inherited
95
+ > 0.6.4 and may trigger Microsoft SmartScreen. The release build removes Node's inherited
96
96
  > signature before SEA injection and fails unless Windows reports the result as `NotSigned`;
97
97
  > it does not ship an invalid signature. Before running it, verify `SHA256SUMS` and the
98
98
  > GitHub build-provenance attestation. Each binary also has an attached SPDX SBOM (the packages
@@ -116,7 +116,7 @@ docker run --rm --network=none -v "$PWD:/w" -w /w -v "$PWD/cejel:/cejel:ro" debi
116
116
  npx @cejel/cejel@latest .
117
117
  ```
118
118
 
119
- > **Distribution note:** Cejel `0.6.3` is the coordinated release version for npm,
119
+ > **Distribution note:** Cejel `0.6.4` is the coordinated release version for npm,
120
120
  > standalone binaries, Docker/OCI, GitHub Action, Homebrew, and MCP Registry. A GitLab CI
121
121
  > template and Code Quality export live in [`docs/gitlab-ci.md`](./docs/gitlab-ci.md).
122
122
 
@@ -187,16 +187,16 @@ gh attestation verify ./cejel-Windows-x86_64.exe -R BargLabs/cejel
187
187
  This is cryptographically signed provenance. It is distinct from Apple Developer ID or
188
188
  Microsoft Authenticode code-signing.
189
189
 
190
- **Docker / OCI.** The current container release is `0.6.3`:
190
+ **Docker / OCI.** The current container release is `0.6.4`:
191
191
 
192
192
  ```bash
193
- docker run --rm -i -v "$PWD:/workspace:ro" ghcr.io/barglabs/cejel:0.6.3
193
+ docker run --rm -i -v "$PWD:/workspace:ro" ghcr.io/barglabs/cejel:0.6.4
194
194
  ```
195
195
 
196
196
  The image defaults to `cejel-mcp` over stdio. To use the CLI instead:
197
197
 
198
198
  ```bash
199
- docker run --rm -v "$PWD:/workspace:ro" --entrypoint cejel ghcr.io/barglabs/cejel:0.6.3 .
199
+ docker run --rm -v "$PWD:/workspace:ro" --entrypoint cejel ghcr.io/barglabs/cejel:0.6.4 .
200
200
  ```
201
201
 
202
202
  The OCI image carries an SBOM of its base-image packages, maximum-mode build provenance, and a
@@ -299,8 +299,10 @@ prints that boundary on every successful verification.
299
299
  - `--rubric-pin <version>` — Explicit opt-in only: pin an alternate rubric instead of the
300
300
  calibrated public default. It
301
301
  accepts the calibrated version or any published prospective rubric
302
- (`witan-rubric-v18-prospective-*` through `v23`) and fails closed, naming what was accepted, on
303
- anything else. `v23` is prospective and uncalibrated, like every rubric after v17: the public
302
+ (`witan-rubric-v18-prospective-*` through `v25`) and fails closed, naming what was accepted, on
303
+ anything else. `v25` is prospective and uncalibrated: it inherits v22 and adds only credit for a
304
+ health or readiness route declared inline in an application file (see "What counts as a health or
305
+ readiness signal" below). `v23` is prospective and uncalibrated, like every rubric after v17: the public
304
306
  default (`WITAN_LAST_CALIBRATED_RUBRIC_VERSION`) is still `witan-rubric-v17-2026-07-24`, and v23
305
307
  inherits none of v17's precision, recall, or false-positive-rate figures. It inherits v22
306
308
  detector/scoring behavior and adds bounded A1 coverage-flag recognition (#276) plus per-signal
@@ -567,7 +569,7 @@ The OCI image is an alternative when Docker is the preferred execution boundary.
567
569
  the host path with the repository OpenClaw should allow Cejel to read:
568
570
 
569
571
  ```bash
570
- 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.6.3"]}'
572
+ 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.6.4"]}'
571
573
  npx -y openclaw@latest mcp doctor cejel-oci --probe
572
574
  ```
573
575
 
@@ -635,6 +637,27 @@ belongs to:
635
637
  `test` script's content against known test-runner invocations rather than crediting it by key
636
638
  presence alone, so no separate disclosure line is needed for it.
637
639
 
640
+ ### What counts as a health or readiness signal
641
+
642
+ The "health or readiness signal" component of A3's production-readiness checks is filename-based
643
+ by design under the calibrated rubric (and every prospective rubric before `v25`). It is credited
644
+ for exactly these forms:
645
+
646
+ - a dedicated health or readiness file, such as `health.ts`, `healthcheck.js`, `readiness.py`
647
+ (the file must mention health or readiness);
648
+ - a `HEALTHCHECK` instruction in a root `Dockerfile`;
649
+ - Kubernetes liveness or readiness probes in a `k8s/`, `kubernetes/` or `helm/` manifest.
650
+
651
+ **A route declared inline in an application file does not count under the calibrated rubric**,
652
+ whatever its content: `app.get("/health", ...)` in `server.ts` or `app.ts` earns nothing there,
653
+ because the component never reads route text. The certificate states this next to the component.
654
+ Prospective `witan-rubric-v25-prospective-2026-10-12` is the one rubric that also credits an inline
655
+ route, in the files the separate info-level "no health or readiness route" finding already reads
656
+ (under `src/`, `app/`, `lib/`, `packages/`, `functions/`, a repo-root `server`/`index`/`app`/`main`
657
+ file, or a `server/`, `backend/` or `api/` tree), with comments stripped and tests, docs, examples
658
+ and scripts excluded. It is explicit opt-in (`--rubric-pin`), carries no precision or recall claim,
659
+ and its public paired rescore has not run.
660
+
638
661
  ## Help validate Cejel
639
662
 
640
663
  Cejel does not collect telemetry. External validation is therefore opt-in and inspectable:
@@ -5,7 +5,7 @@ import {
5
5
  deriveProductIdentity,
6
6
  runCejelScan,
7
7
  serializeWitanReport
8
- } from "../chunk-FA72HEWJ.js";
8
+ } from "../chunk-4YK23CST.js";
9
9
  import {
10
10
  listCejelLlmPackFiles
11
11
  } from "../chunk-M6YYPJSN.js";
@@ -532,6 +532,7 @@ var WITAN_RUBRIC_VERSION_V21 = "witan-rubric-v21-prospective-2026-08-10";
532
532
  var WITAN_RUBRIC_VERSION_V22 = "witan-rubric-v22-prospective-2026-08-10";
533
533
  var WITAN_RUBRIC_VERSION_V23 = "witan-rubric-v23-prospective-2026-09-06";
534
534
  var WITAN_RUBRIC_VERSION_V24 = "witan-rubric-v24-prospective-2026-09-15";
535
+ var WITAN_RUBRIC_VERSION_V25 = "witan-rubric-v25-prospective-2026-10-12";
535
536
  var WITAN_LAST_CALIBRATED_RUBRIC_VERSION = WITAN_RUBRIC_VERSION_V17;
536
537
  var WITAN_PROSPECTIVE_RUBRIC_VERSIONS = Object.freeze([
537
538
  WITAN_RUBRIC_VERSION_V18,
@@ -540,7 +541,8 @@ var WITAN_PROSPECTIVE_RUBRIC_VERSIONS = Object.freeze([
540
541
  WITAN_RUBRIC_VERSION_V21,
541
542
  WITAN_RUBRIC_VERSION_V22,
542
543
  WITAN_RUBRIC_VERSION_V23,
543
- WITAN_RUBRIC_VERSION_V24
544
+ WITAN_RUBRIC_VERSION_V24,
545
+ WITAN_RUBRIC_VERSION_V25
544
546
  ]);
545
547
  var WITAN_SELECTABLE_RUBRIC_VERSIONS = Object.freeze([
546
548
  WITAN_LAST_CALIBRATED_RUBRIC_VERSION,
@@ -642,14 +644,15 @@ init_esm_shims();
642
644
  init_esm_shims();
643
645
  import { createHash } from "crypto";
644
646
  var WITAN_RUBRIC_BEHAVIOUR_FINGERPRINTS = Object.freeze({
645
- [WITAN_RUBRIC_VERSION_V17]: "sha256:2da86acf64c39d2edb7824df46250ea23c396264266a2cd925953e9c6ad25858",
646
- [WITAN_RUBRIC_VERSION_V18]: "sha256:60917d1d81efe7cda6f6adbfaa05293e2d9bf1db37b39d084e47f9011a996b67",
647
- [WITAN_RUBRIC_VERSION_V19]: "sha256:e050ce8563de0736d9cfb6c23e2ba04725d88465d378a8632576269b9bc9f269",
648
- [WITAN_RUBRIC_VERSION_V20]: "sha256:0433adc34b58c0fd5500a0bdeaa910c854eedbadbeaabb9045238d4ba9be8878",
649
- [WITAN_RUBRIC_VERSION_V21]: "sha256:d3796b78a45ea3593f6abe71c77c2d00a0056d0f2d88476a01329dc342166aa6",
650
- [WITAN_RUBRIC_VERSION_V22]: "sha256:932bc09cbe555c6058a95be581ccf7a286c43887f90d32698f5273b7623824bf",
651
- [WITAN_RUBRIC_VERSION_V23]: "sha256:db97dc999d37e3c39c3bd3e4b1778c94eb9ad3176fb5c7d7264a7e510b162fc1",
652
- [WITAN_RUBRIC_VERSION_V24]: "sha256:e313fab25ae1779a11e86b23696881cd6f8fe2a845609dc93e2ff6f3ff8c16d5"
647
+ [WITAN_RUBRIC_VERSION_V17]: "sha256:6a31f7cb96ebf17046ba0620d74b1fadb66582c4b4ae5cb0b5af04480df6dbf2",
648
+ [WITAN_RUBRIC_VERSION_V18]: "sha256:9c54aa1493ff42b001ae2d1828f4bda92b3ebff500551eb36ef8a2b9d2fc391f",
649
+ [WITAN_RUBRIC_VERSION_V19]: "sha256:ed3fa7ff11aa0c0ecf7fc23fccab2c40337c55c5b06abae14eb10e9d73bbcffa",
650
+ [WITAN_RUBRIC_VERSION_V20]: "sha256:eb6ed39afd0e3f3d73e6a85df90787a3490087eaa34aad19fb5fbb31b4502ce5",
651
+ [WITAN_RUBRIC_VERSION_V21]: "sha256:7a890ac663793f807e240e38047ff9fbc069853d118ebf9a765cc103a8bed2a3",
652
+ [WITAN_RUBRIC_VERSION_V22]: "sha256:ac4db093dc7c37369579b49ccd7855d36eec49d9f52136964251ee7bbd69e101",
653
+ [WITAN_RUBRIC_VERSION_V23]: "sha256:7d48de4ac8ef3233e7ef8f4d4312830bf76294485e9766a47a671cd5440676aa",
654
+ [WITAN_RUBRIC_VERSION_V24]: "sha256:0af37b616891a1940f7ba43c86ef2134d6e40f235feef17bf1774cae951afee2",
655
+ [WITAN_RUBRIC_VERSION_V25]: "sha256:31a751882d02c8f053dcc8f3e90b3e4ecd57279f3250e420e95a3af875b9f019"
653
656
  });
654
657
  function rubricBehaviourFingerprint(rubricVersion) {
655
658
  return WITAN_RUBRIC_BEHAVIOUR_FINGERPRINTS[rubricVersion];
@@ -717,7 +720,7 @@ var WITAN_RUBRIC = [
717
720
 
718
721
  // src/witan/scoring.ts
719
722
  function usesV17DetectorClosure(rubricVersion) {
720
- return rubricVersion === WITAN_RUBRIC_VERSION_V17 || rubricVersion === WITAN_RUBRIC_VERSION_V18 || rubricVersion === WITAN_RUBRIC_VERSION_V19 || rubricVersion === WITAN_RUBRIC_VERSION_V20 || rubricVersion === WITAN_RUBRIC_VERSION_V21 || rubricVersion === WITAN_RUBRIC_VERSION_V22 || rubricVersion === WITAN_RUBRIC_VERSION_V24 || rubricVersion === WITAN_RUBRIC_VERSION_V23;
723
+ return rubricVersion === WITAN_RUBRIC_VERSION_V17 || rubricVersion === WITAN_RUBRIC_VERSION_V18 || rubricVersion === WITAN_RUBRIC_VERSION_V19 || rubricVersion === WITAN_RUBRIC_VERSION_V20 || rubricVersion === WITAN_RUBRIC_VERSION_V21 || rubricVersion === WITAN_RUBRIC_VERSION_V22 || rubricVersion === WITAN_RUBRIC_VERSION_V25 || rubricVersion === WITAN_RUBRIC_VERSION_V24 || rubricVersion === WITAN_RUBRIC_VERSION_V23;
721
724
  }
722
725
  var MAX_SIGNAL_ADJUSTMENT = 0.8;
723
726
  function createWitanReport(input, inputSignals, rubric = WITAN_RUBRIC, toolVersion) {
@@ -888,7 +891,7 @@ function statusForScore(score) {
888
891
  }
889
892
  function statusAfterInputAdjustment(nativeStatus, nativeScore, adjustment, rubricVersion) {
890
893
  if (adjustment === 0) return nativeStatus;
891
- if (rubricVersion !== WITAN_RUBRIC_VERSION_V8 && rubricVersion !== WITAN_RUBRIC_VERSION_V9 && rubricVersion !== WITAN_RUBRIC_VERSION_V10 && rubricVersion !== WITAN_RUBRIC_VERSION_V11 && rubricVersion !== WITAN_RUBRIC_VERSION_V12 && rubricVersion !== WITAN_RUBRIC_VERSION_V13 && rubricVersion !== WITAN_RUBRIC_VERSION_V14 && rubricVersion !== WITAN_RUBRIC_VERSION_V15 && rubricVersion !== WITAN_RUBRIC_VERSION_V16 && rubricVersion !== WITAN_RUBRIC_VERSION_V17 && rubricVersion !== WITAN_RUBRIC_VERSION_V18 && rubricVersion !== WITAN_RUBRIC_VERSION_V19 && rubricVersion !== WITAN_RUBRIC_VERSION_V20 && rubricVersion !== WITAN_RUBRIC_VERSION_V21 && rubricVersion !== WITAN_RUBRIC_VERSION_V22 && rubricVersion !== WITAN_RUBRIC_VERSION_V24 && rubricVersion !== WITAN_RUBRIC_VERSION_V23) {
894
+ if (rubricVersion !== WITAN_RUBRIC_VERSION_V8 && rubricVersion !== WITAN_RUBRIC_VERSION_V9 && rubricVersion !== WITAN_RUBRIC_VERSION_V10 && rubricVersion !== WITAN_RUBRIC_VERSION_V11 && rubricVersion !== WITAN_RUBRIC_VERSION_V12 && rubricVersion !== WITAN_RUBRIC_VERSION_V13 && rubricVersion !== WITAN_RUBRIC_VERSION_V14 && rubricVersion !== WITAN_RUBRIC_VERSION_V15 && rubricVersion !== WITAN_RUBRIC_VERSION_V16 && rubricVersion !== WITAN_RUBRIC_VERSION_V17 && rubricVersion !== WITAN_RUBRIC_VERSION_V18 && rubricVersion !== WITAN_RUBRIC_VERSION_V19 && rubricVersion !== WITAN_RUBRIC_VERSION_V20 && rubricVersion !== WITAN_RUBRIC_VERSION_V21 && rubricVersion !== WITAN_RUBRIC_VERSION_V22 && rubricVersion !== WITAN_RUBRIC_VERSION_V25 && rubricVersion !== WITAN_RUBRIC_VERSION_V24 && rubricVersion !== WITAN_RUBRIC_VERSION_V23) {
892
895
  return statusForScore(roundScore(Math.max(0, nativeScore - adjustment)));
893
896
  }
894
897
  const statusFloor = {
@@ -945,7 +948,7 @@ function mergeSignalsByCriterion(signals) {
945
948
  return merged;
946
949
  }
947
950
  function usesMetricScoring(rubricVersion) {
948
- return rubricVersion === WITAN_RUBRIC_VERSION_V1 || rubricVersion === WITAN_RUBRIC_VERSION_V2 || rubricVersion === WITAN_RUBRIC_VERSION_V3 || rubricVersion === WITAN_RUBRIC_VERSION_V4 || rubricVersion === WITAN_RUBRIC_VERSION_V5 || rubricVersion === WITAN_RUBRIC_VERSION_V6 || rubricVersion === WITAN_RUBRIC_VERSION_V7 || rubricVersion === WITAN_RUBRIC_VERSION_V8 || rubricVersion === WITAN_RUBRIC_VERSION_V9 || rubricVersion === WITAN_RUBRIC_VERSION_V10 || rubricVersion === WITAN_RUBRIC_VERSION_V11 || rubricVersion === WITAN_RUBRIC_VERSION_V12 || rubricVersion === WITAN_RUBRIC_VERSION_V13 || rubricVersion === WITAN_RUBRIC_VERSION_V14 || rubricVersion === WITAN_RUBRIC_VERSION_V15 || rubricVersion === WITAN_RUBRIC_VERSION_V16 || rubricVersion === WITAN_RUBRIC_VERSION_V17 || rubricVersion === WITAN_RUBRIC_VERSION_V18 || rubricVersion === WITAN_RUBRIC_VERSION_V19 || rubricVersion === WITAN_RUBRIC_VERSION_V20 || rubricVersion === WITAN_RUBRIC_VERSION_V21 || rubricVersion === WITAN_RUBRIC_VERSION_V22 || rubricVersion === WITAN_RUBRIC_VERSION_V24 || rubricVersion === WITAN_RUBRIC_VERSION_V23 || rubricVersion === WITAN_TRADING_RUBRIC_VERSION_V0;
951
+ return rubricVersion === WITAN_RUBRIC_VERSION_V1 || rubricVersion === WITAN_RUBRIC_VERSION_V2 || rubricVersion === WITAN_RUBRIC_VERSION_V3 || rubricVersion === WITAN_RUBRIC_VERSION_V4 || rubricVersion === WITAN_RUBRIC_VERSION_V5 || rubricVersion === WITAN_RUBRIC_VERSION_V6 || rubricVersion === WITAN_RUBRIC_VERSION_V7 || rubricVersion === WITAN_RUBRIC_VERSION_V8 || rubricVersion === WITAN_RUBRIC_VERSION_V9 || rubricVersion === WITAN_RUBRIC_VERSION_V10 || rubricVersion === WITAN_RUBRIC_VERSION_V11 || rubricVersion === WITAN_RUBRIC_VERSION_V12 || rubricVersion === WITAN_RUBRIC_VERSION_V13 || rubricVersion === WITAN_RUBRIC_VERSION_V14 || rubricVersion === WITAN_RUBRIC_VERSION_V15 || rubricVersion === WITAN_RUBRIC_VERSION_V16 || rubricVersion === WITAN_RUBRIC_VERSION_V17 || rubricVersion === WITAN_RUBRIC_VERSION_V18 || rubricVersion === WITAN_RUBRIC_VERSION_V19 || rubricVersion === WITAN_RUBRIC_VERSION_V20 || rubricVersion === WITAN_RUBRIC_VERSION_V21 || rubricVersion === WITAN_RUBRIC_VERSION_V22 || rubricVersion === WITAN_RUBRIC_VERSION_V25 || rubricVersion === WITAN_RUBRIC_VERSION_V24 || rubricVersion === WITAN_RUBRIC_VERSION_V23 || rubricVersion === WITAN_TRADING_RUBRIC_VERSION_V0;
949
952
  }
950
953
  function unmeasuredStatus(rubricVersion) {
951
954
  return rubricVersion === WITAN_TRADING_RUBRIC_VERSION_V0 ? "unverified" : "insufficient_data";
@@ -1333,7 +1336,7 @@ function calibratedCriterionStateV11(criterionId, metrics) {
1333
1336
  return void 0;
1334
1337
  }
1335
1338
  function ensureFindingsExplainStatus(criterionId, score, status, findings, evidence, rubricVersion) {
1336
- if (rubricVersion !== WITAN_RUBRIC_VERSION_V8 && rubricVersion !== WITAN_RUBRIC_VERSION_V9 && rubricVersion !== WITAN_RUBRIC_VERSION_V10 && rubricVersion !== WITAN_RUBRIC_VERSION_V11 && rubricVersion !== WITAN_RUBRIC_VERSION_V12 && rubricVersion !== WITAN_RUBRIC_VERSION_V13 && rubricVersion !== WITAN_RUBRIC_VERSION_V14 && rubricVersion !== WITAN_RUBRIC_VERSION_V15 && rubricVersion !== WITAN_RUBRIC_VERSION_V16 && rubricVersion !== WITAN_RUBRIC_VERSION_V17 && rubricVersion !== WITAN_RUBRIC_VERSION_V18 && rubricVersion !== WITAN_RUBRIC_VERSION_V19 && rubricVersion !== WITAN_RUBRIC_VERSION_V20 && rubricVersion !== WITAN_RUBRIC_VERSION_V21 && rubricVersion !== WITAN_RUBRIC_VERSION_V22 && rubricVersion !== WITAN_RUBRIC_VERSION_V24 && rubricVersion !== WITAN_RUBRIC_VERSION_V23 && findings.length > 0) {
1339
+ if (rubricVersion !== WITAN_RUBRIC_VERSION_V8 && rubricVersion !== WITAN_RUBRIC_VERSION_V9 && rubricVersion !== WITAN_RUBRIC_VERSION_V10 && rubricVersion !== WITAN_RUBRIC_VERSION_V11 && rubricVersion !== WITAN_RUBRIC_VERSION_V12 && rubricVersion !== WITAN_RUBRIC_VERSION_V13 && rubricVersion !== WITAN_RUBRIC_VERSION_V14 && rubricVersion !== WITAN_RUBRIC_VERSION_V15 && rubricVersion !== WITAN_RUBRIC_VERSION_V16 && rubricVersion !== WITAN_RUBRIC_VERSION_V17 && rubricVersion !== WITAN_RUBRIC_VERSION_V18 && rubricVersion !== WITAN_RUBRIC_VERSION_V19 && rubricVersion !== WITAN_RUBRIC_VERSION_V20 && rubricVersion !== WITAN_RUBRIC_VERSION_V21 && rubricVersion !== WITAN_RUBRIC_VERSION_V22 && rubricVersion !== WITAN_RUBRIC_VERSION_V25 && rubricVersion !== WITAN_RUBRIC_VERSION_V24 && rubricVersion !== WITAN_RUBRIC_VERSION_V23 && findings.length > 0) {
1337
1340
  return [...findings];
1338
1341
  }
1339
1342
  if (status !== "critical" && status !== "warning") return [...findings];
@@ -1479,7 +1482,7 @@ var CERTIFICATE_GLOSSARY = [
1479
1482
  {
1480
1483
  key: "production-readiness-basic-checks",
1481
1484
  term: "Production-readiness basic checks",
1482
- definition: "A count of six named checks: a build or type-check command, a CI workflow, deployment configuration, an environment template, a health or readiness signal, and an error boundary.",
1485
+ definition: "A count of six named checks: a build or type-check command, a CI workflow, deployment configuration, an environment template, a health or readiness signal, and an error boundary. In the calibrated rubric the health or readiness signal is credited only for a dedicated health or readiness file (such as health.ts or readiness.ts), a Dockerfile HEALTHCHECK, or Kubernetes liveness or readiness probes. A health route declared inline in an application file does not count there. The prospective witan-rubric-v25 also credits such an inline route.",
1483
1486
  metricNames: ["prod_readiness_primitives"]
1484
1487
  },
1485
1488
  {
@@ -1611,7 +1614,7 @@ var CERTIFICATE_GLOSSARY = [
1611
1614
  {
1612
1615
  key: "protected-path-review-gate",
1613
1616
  term: "Protected-path review gate",
1614
- definition: "A binary check for a CODEOWNERS file or documentation of required review or branch protection. This is the repository-visible proxy for human review of sensitive-path changes.",
1617
+ definition: "A binary check for a CODEOWNERS file in a location GitHub reads (the repository root, .github/ or docs/), or a document stating a required-review or branch-protection policy. A changelog, an experiment or calibration record, a review note or a report does not count. This is the repository-visible proxy for human review of sensitive-path changes.",
1615
1618
  metricNames: ["protected_path_review_gate"]
1616
1619
  }
1617
1620
  ];
@@ -1710,7 +1713,7 @@ var BINARY_METRIC_COPY = {
1710
1713
  },
1711
1714
  protected_path_review_gate: {
1712
1715
  positive: "present \u2014 CODEOWNERS or a documented required-review policy was detected",
1713
- negative: "missing \u2014 no CODEOWNERS or documented required-review policy detected"
1716
+ negative: "missing \u2014 no CODEOWNERS file in a location GitHub reads, and no documented required-review or branch-protection policy detected"
1714
1717
  }
1715
1718
  };
1716
1719
  var CONDITIONAL_METRIC_COPY = {
@@ -2902,7 +2905,7 @@ function stripBom(text) {
2902
2905
 
2903
2906
  // src/witan/repo-signals.ts
2904
2907
  function usesV17DetectorClosure2(rubricVersion) {
2905
- return rubricVersion === WITAN_RUBRIC_VERSION_V17 || rubricVersion === WITAN_RUBRIC_VERSION_V18 || rubricVersion === WITAN_RUBRIC_VERSION_V19 || rubricVersion === WITAN_RUBRIC_VERSION_V20 || rubricVersion === WITAN_RUBRIC_VERSION_V21 || rubricVersion === WITAN_RUBRIC_VERSION_V22 || rubricVersion === WITAN_RUBRIC_VERSION_V23 || rubricVersion === WITAN_RUBRIC_VERSION_V24;
2908
+ return rubricVersion === WITAN_RUBRIC_VERSION_V17 || rubricVersion === WITAN_RUBRIC_VERSION_V18 || rubricVersion === WITAN_RUBRIC_VERSION_V19 || rubricVersion === WITAN_RUBRIC_VERSION_V20 || rubricVersion === WITAN_RUBRIC_VERSION_V21 || rubricVersion === WITAN_RUBRIC_VERSION_V22 || rubricVersion === WITAN_RUBRIC_VERSION_V23 || rubricVersion === WITAN_RUBRIC_VERSION_V24 || rubricVersion === WITAN_RUBRIC_VERSION_V25;
2906
2909
  }
2907
2910
  var LEGACY_INVENTORY_ABSENCE_CONTEXT = {
2908
2911
  rubricGeneration: "legacy",
@@ -3149,15 +3152,16 @@ function buildWitanInputFromRepoUntracked(options) {
3149
3152
  rubricGeneration: usesV17Detectors ? "current" : "legacy",
3150
3153
  inventoryProvenance: fileInventory.repoFileInventoryScope === "tracked-scan-eligible" ? "tracked-scan-eligible" : "directory-walk"
3151
3154
  };
3152
- const usesV18NativeRls = rubricVersion === WITAN_RUBRIC_VERSION_V18 || rubricVersion === WITAN_RUBRIC_VERSION_V19 || rubricVersion === WITAN_RUBRIC_VERSION_V20 || rubricVersion === WITAN_RUBRIC_VERSION_V21 || rubricVersion === WITAN_RUBRIC_VERSION_V22 || rubricVersion === WITAN_RUBRIC_VERSION_V23 || rubricVersion === WITAN_RUBRIC_VERSION_V24;
3153
- const usesV19CommitYear = rubricVersion === WITAN_RUBRIC_VERSION_V19 || rubricVersion === WITAN_RUBRIC_VERSION_V20 || rubricVersion === WITAN_RUBRIC_VERSION_V21 || rubricVersion === WITAN_RUBRIC_VERSION_V22 || rubricVersion === WITAN_RUBRIC_VERSION_V23 || rubricVersion === WITAN_RUBRIC_VERSION_V24;
3154
- const usesV20A3ExplicitGaps = rubricVersion === WITAN_RUBRIC_VERSION_V20 || rubricVersion === WITAN_RUBRIC_VERSION_V21 || rubricVersion === WITAN_RUBRIC_VERSION_V22 || rubricVersion === WITAN_RUBRIC_VERSION_V23 || rubricVersion === WITAN_RUBRIC_VERSION_V24;
3155
- const usesV21ExecutedEscalations = rubricVersion === WITAN_RUBRIC_VERSION_V21 || rubricVersion === WITAN_RUBRIC_VERSION_V22 || rubricVersion === WITAN_RUBRIC_VERSION_V23 || rubricVersion === WITAN_RUBRIC_VERSION_V24;
3156
- const usesV22PackageStartEntrypoint = rubricVersion === WITAN_RUBRIC_VERSION_V22 || rubricVersion === WITAN_RUBRIC_VERSION_V23 || rubricVersion === WITAN_RUBRIC_VERSION_V24;
3155
+ const usesV18NativeRls = rubricVersion === WITAN_RUBRIC_VERSION_V18 || rubricVersion === WITAN_RUBRIC_VERSION_V19 || rubricVersion === WITAN_RUBRIC_VERSION_V20 || rubricVersion === WITAN_RUBRIC_VERSION_V21 || rubricVersion === WITAN_RUBRIC_VERSION_V22 || rubricVersion === WITAN_RUBRIC_VERSION_V23 || rubricVersion === WITAN_RUBRIC_VERSION_V24 || rubricVersion === WITAN_RUBRIC_VERSION_V25;
3156
+ const usesV19CommitYear = rubricVersion === WITAN_RUBRIC_VERSION_V19 || rubricVersion === WITAN_RUBRIC_VERSION_V20 || rubricVersion === WITAN_RUBRIC_VERSION_V21 || rubricVersion === WITAN_RUBRIC_VERSION_V22 || rubricVersion === WITAN_RUBRIC_VERSION_V23 || rubricVersion === WITAN_RUBRIC_VERSION_V24 || rubricVersion === WITAN_RUBRIC_VERSION_V25;
3157
+ const usesV20A3ExplicitGaps = rubricVersion === WITAN_RUBRIC_VERSION_V20 || rubricVersion === WITAN_RUBRIC_VERSION_V21 || rubricVersion === WITAN_RUBRIC_VERSION_V22 || rubricVersion === WITAN_RUBRIC_VERSION_V23 || rubricVersion === WITAN_RUBRIC_VERSION_V24 || rubricVersion === WITAN_RUBRIC_VERSION_V25;
3158
+ const usesV21ExecutedEscalations = rubricVersion === WITAN_RUBRIC_VERSION_V21 || rubricVersion === WITAN_RUBRIC_VERSION_V22 || rubricVersion === WITAN_RUBRIC_VERSION_V23 || rubricVersion === WITAN_RUBRIC_VERSION_V24 || rubricVersion === WITAN_RUBRIC_VERSION_V25;
3159
+ const usesV22PackageStartEntrypoint = rubricVersion === WITAN_RUBRIC_VERSION_V22 || rubricVersion === WITAN_RUBRIC_VERSION_V23 || rubricVersion === WITAN_RUBRIC_VERSION_V24 || rubricVersion === WITAN_RUBRIC_VERSION_V25;
3157
3160
  const usesV23CommandCoverage = rubricVersion === WITAN_RUBRIC_VERSION_V23;
3158
3161
  const usesV23PemPrivateKeyGrammar = rubricVersion === WITAN_RUBRIC_VERSION_V23;
3159
3162
  const usesV23WithheldPathAbstention = rubricVersion === WITAN_RUBRIC_VERSION_V23;
3160
3163
  const usesV24SecretContentContext = rubricVersion === WITAN_RUBRIC_VERSION_V24;
3164
+ const usesV25InlineHealthRoute = rubricVersion === WITAN_RUBRIC_VERSION_V25;
3161
3165
  const structuralArchetype = classifyRepoArchetype(inventoryFiles, rubricVersion);
3162
3166
  const readableArchetype = rubricVersion === WITAN_RUBRIC_VERSION_V13 || rubricVersion === WITAN_RUBRIC_VERSION_V14 || rubricVersion === WITAN_RUBRIC_VERSION_V15 || rubricVersion === WITAN_RUBRIC_VERSION_V16 || usesV17DetectorClosure2(rubricVersion) ? applyReadableSourceRepresentationGate(
3163
3167
  options.repoPath,
@@ -3197,6 +3201,7 @@ function buildWitanInputFromRepoUntracked(options) {
3197
3201
  usesV23PemPrivateKeyGrammar,
3198
3202
  usesV23WithheldPathAbstention,
3199
3203
  usesV24SecretContentContext,
3204
+ usesV25InlineHealthRoute,
3200
3205
  reviewableSourceProof,
3201
3206
  inventoryAbsenceContext,
3202
3207
  scanLimitations
@@ -3811,7 +3816,7 @@ function buildNotApplicableSignal(criterionId, reason) {
3811
3816
  notApplicable: true
3812
3817
  };
3813
3818
  }
3814
- function collectRepoSignals(repoPath, generatedAt, repoFiles, useV27Detectors, useV33Detectors, useV36Detectors, useV39Detectors, useV47Detectors, useV18NativeRls, useV19CommitYear, useV20A3ExplicitGaps, useV21ExecutedEscalations, useV22PackageStartEntrypoint, useV23CommandCoverage, useV23PemPrivateKeyGrammar, useV23WithheldPathAbstention, useV24SecretContentContext, reviewableSourceProof, inventoryAbsenceContext = LEGACY_INVENTORY_ABSENCE_CONTEXT, scanLimitations = /* @__PURE__ */ new Set()) {
3819
+ function collectRepoSignals(repoPath, generatedAt, repoFiles, useV27Detectors, useV33Detectors, useV36Detectors, useV39Detectors, useV47Detectors, useV18NativeRls, useV19CommitYear, useV20A3ExplicitGaps, useV21ExecutedEscalations, useV22PackageStartEntrypoint, useV23CommandCoverage, useV23PemPrivateKeyGrammar, useV23WithheldPathAbstention, useV24SecretContentContext, useV25InlineHealthRoute, reviewableSourceProof, inventoryAbsenceContext = LEGACY_INVENTORY_ABSENCE_CONTEXT, scanLimitations = /* @__PURE__ */ new Set()) {
3815
3820
  const signals = [];
3816
3821
  const mono = resolveMonorepoContext(repoPath, scanLimitations);
3817
3822
  const collectCriterion = (criterionId, collect) => withContentReadCriterion(criterionId, collect);
@@ -3854,7 +3859,8 @@ function collectRepoSignals(repoPath, generatedAt, repoFiles, useV27Detectors, u
3854
3859
  useV20A3ExplicitGaps,
3855
3860
  useV22PackageStartEntrypoint,
3856
3861
  useV23WithheldPathAbstention,
3857
- inventoryAbsenceContext
3862
+ inventoryAbsenceContext,
3863
+ useV25InlineHealthRoute
3858
3864
  )
3859
3865
  );
3860
3866
  const a4Signal = collectCriterion(
@@ -4752,7 +4758,7 @@ function collectCryptoHygieneEvidence(repoPath, implFiles, useV39Detectors = fal
4752
4758
  }
4753
4759
  return { evidence, findings, hasSurface, clean: hasSurface && !insecureFound };
4754
4760
  }
4755
- function collectA3ProdReadinessEvidence(repoPath, repoFiles, useV27Detectors, useV20ExplicitGaps = false, useV22PackageStartEntrypoint = false, useV23WithheldPathAbstention = false, inventoryAbsenceContext = LEGACY_INVENTORY_ABSENCE_CONTEXT) {
4761
+ function collectA3ProdReadinessEvidence(repoPath, repoFiles, useV27Detectors, useV20ExplicitGaps = false, useV22PackageStartEntrypoint = false, useV23WithheldPathAbstention = false, inventoryAbsenceContext = LEGACY_INVENTORY_ABSENCE_CONTEXT, useV25InlineHealthRoute = false) {
4756
4762
  const v20DirectHttpEntrypoint = useV20ExplicitGaps ? findV20DirectHttpServerEntrypointFile(repoPath, repoFiles) : null;
4757
4763
  const v22PackageStartHttpEntrypoint = useV22PackageStartEntrypoint ? findV22PackageStartHttpServerEntrypointFile(repoPath, repoFiles) : null;
4758
4764
  const v20RuntimeContainer = useV20ExplicitGaps ? findRuntimeContainerEntrypointFile(repoPath, repoFiles, true) : null;
@@ -4790,8 +4796,16 @@ function collectA3ProdReadinessEvidence(repoPath, repoFiles, useV27Detectors, us
4790
4796
  )
4791
4797
  );
4792
4798
  const healthCheck = healthChecks[0];
4793
- const healthReadinessRouteReads = (file) => isAuthoredProductionPath(file) && (isImplementationFile(file) || HEALTH_ROUTE_FUNCTIONS_DIR_PATTERN.test(file));
4799
+ const healthReadinessRouteReads = (file) => isAuthoredProductionPath(file) && (isImplementationFile(file) || HEALTH_ROUTE_FUNCTIONS_DIR_PATTERN.test(file) || HEALTH_ROUTE_ENTRYPOINT_HOME_PATTERN.test(file));
4794
4800
  const observabilityDepthReads = (file) => (!useV27Detectors || isAuthoredProductionPath(file)) && isImplementationFile(file);
4801
+ const inlineHealthRouteFile = useV25InlineHealthRoute && healthChecks.length === 0 ? withContentReadSignal(
4802
+ "A3",
4803
+ "prod_readiness_primitives",
4804
+ () => repoFiles.find(
4805
+ (file) => healthReadinessRouteReads(file) && fileMatchesOutsideComments(repoPath, file, V20_HEALTH_OR_READINESS_ROUTE_PATTERN)
4806
+ )
4807
+ ) : void 0;
4808
+ const hasHealthOrReadinessSignal = healthChecks.length > 0 || inlineHealthRouteFile !== void 0;
4795
4809
  const { hasV20HealthOrReadinessRoute, hasV22PackageStartHealthOrReadinessRoute } = withContentReadSignal("A3", "health_readiness_route", () => ({
4796
4810
  hasV20HealthOrReadinessRoute: useV20ExplicitGaps && repoFiles.some(
4797
4811
  (file) => healthReadinessRouteReads(file) && fileContains(repoPath, file, V20_HEALTH_OR_READINESS_ROUTE_PATTERN)
@@ -4855,12 +4869,28 @@ function collectA3ProdReadinessEvidence(repoPath, repoFiles, useV27Detectors, us
4855
4869
  /rollback|roll back|migration safety|down migration|reversible|undo migration/i
4856
4870
  )
4857
4871
  );
4872
+ const rootOnlyScriptsNote = rootOnlyPackageScriptsDisclosure(repoFiles, packageJson);
4858
4873
  if (packageJson && (scripts.has("build") || scripts.has("typecheck"))) {
4859
4874
  evidence.push(
4860
4875
  evidenceForRelative(repoPath, packageJson, "prod_check", "Build or typecheck script")
4861
4876
  );
4862
4877
  }
4863
- if (workflow) evidence.push(evidenceForRelative(repoPath, workflow, "ci_run", "CI workflow"));
4878
+ if (workflow) {
4879
+ evidence.push(
4880
+ evidenceForRelative(
4881
+ repoPath,
4882
+ workflow,
4883
+ "ci_run",
4884
+ ciWorkflowCitationLabel(
4885
+ "CI workflow",
4886
+ "counted",
4887
+ workflows.length,
4888
+ 1,
4889
+ unreadCiWorkflowReasons((file) => !useV27Detectors || isAuthoredProductionPath(file))
4890
+ )
4891
+ )
4892
+ );
4893
+ }
4864
4894
  if (releaseDeployConfig)
4865
4895
  evidence.push(
4866
4896
  evidenceForRelative(
@@ -4889,6 +4919,24 @@ function collectA3ProdReadinessEvidence(repoPath, repoFiles, useV27Detectors, us
4889
4919
  evidenceForRelative(repoPath, healthCheck, "prod_check", "Health/readiness signal")
4890
4920
  )
4891
4921
  );
4922
+ } else if (inlineHealthRouteFile) {
4923
+ withContentReadSignal(
4924
+ "A3",
4925
+ "prod_readiness_primitives",
4926
+ () => evidence.push(
4927
+ evidenceForRelativeAtLine(
4928
+ repoPath,
4929
+ inlineHealthRouteFile,
4930
+ "prod_check",
4931
+ "Health/readiness route",
4932
+ findFirstMatchingLineOutsideComments(
4933
+ repoPath,
4934
+ inlineHealthRouteFile,
4935
+ V20_HEALTH_OR_READINESS_ROUTE_PATTERN
4936
+ )
4937
+ )
4938
+ )
4939
+ );
4892
4940
  }
4893
4941
  if (errorBoundary) {
4894
4942
  evidence.push(
@@ -5016,7 +5064,7 @@ function collectA3ProdReadinessEvidence(repoPath, repoFiles, useV27Detectors, us
5016
5064
  workflows.length > 0,
5017
5065
  deployConfigs.length > 0,
5018
5066
  envTemplate,
5019
- healthChecks.length > 0,
5067
+ hasHealthOrReadinessSignal,
5020
5068
  errorBoundary !== void 0
5021
5069
  ].filter(Boolean).length,
5022
5070
  6,
@@ -5033,9 +5081,10 @@ function collectA3ProdReadinessEvidence(repoPath, repoFiles, useV27Detectors, us
5033
5081
  { label: "CI workflow", count: workflows.length > 0 ? 1 : 0 },
5034
5082
  { label: "deployment configuration", count: deployConfigs.length > 0 ? 1 : 0 },
5035
5083
  { label: "environment template", count: envTemplate ? 1 : 0 },
5036
- { label: "health or readiness signal", count: healthChecks.length > 0 ? 1 : 0 },
5084
+ { label: "health or readiness signal", count: hasHealthOrReadinessSignal ? 1 : 0 },
5037
5085
  { label: "error boundary", count: errorBoundary !== void 0 ? 1 : 0 }
5038
- ]
5086
+ ],
5087
+ ...rootOnlyScriptsNote ? { condition: rootOnlyScriptsNote } : {}
5039
5088
  }
5040
5089
  ),
5041
5090
  metric(
@@ -5442,8 +5491,16 @@ function collectB2PrTraceEvidence(repoPath, repoFiles) {
5442
5491
  const branchProtectionDoc = repoFiles.find(
5443
5492
  (file) => /branch.*protection|review.*gate/i.test(file) || GITHUB_CODEOWNERS_PATH_PATTERN.test(file)
5444
5493
  );
5494
+ const citedWorkflows = workflows.slice(0, 3);
5495
+ const workflowLabel = ciWorkflowCitationLabel(
5496
+ "Pull-request CI workflow",
5497
+ "counted",
5498
+ workflows.length,
5499
+ citedWorkflows.length,
5500
+ unreadCiWorkflowReasons(() => true)
5501
+ );
5445
5502
  const evidence = [
5446
- ...workflows.slice(0, 3).map((file) => evidenceForRelative(repoPath, file, "ci_run", "Pull-request CI workflow")),
5503
+ ...citedWorkflows.map((file) => evidenceForRelative(repoPath, file, "ci_run", workflowLabel)),
5447
5504
  ...prTemplate ? [evidenceForRelative(repoPath, prTemplate, "pull_request", "Pull request template")] : [],
5448
5505
  ...branchProtectionDoc ? [
5449
5506
  evidenceForRelative(
@@ -5516,11 +5573,20 @@ function collectB3CiDisciplineEvidence(repoPath, repoFiles, mono) {
5516
5573
  if (packageJson && scripts.has("lint")) {
5517
5574
  evidence.push(evidenceForRelative(repoPath, packageJson, "ci_run", "Lint script"));
5518
5575
  }
5576
+ const unreadWorkflows = unreadCiWorkflowReasons(() => true);
5577
+ const workflowsRead = workflows.length + rootWorkflows.length;
5519
5578
  if (workflow) {
5520
5579
  withContentReadSignals(
5521
5580
  "B3",
5522
5581
  ["ci_script_depth", "default_branch_ci_depth"],
5523
- () => evidence.push(evidenceForRelative(repoPath, workflow, "ci_run", "CI workflow"))
5582
+ () => evidence.push(
5583
+ evidenceForRelative(
5584
+ repoPath,
5585
+ workflow,
5586
+ "ci_run",
5587
+ ciWorkflowCitationLabel("CI workflow", "read", workflowsRead, 1, unreadWorkflows)
5588
+ )
5589
+ )
5524
5590
  );
5525
5591
  } else if (rootWorkflows[0] && mono) {
5526
5592
  const rootWorkflow = rootWorkflows[0];
@@ -5528,7 +5594,18 @@ function collectB3CiDisciplineEvidence(repoPath, repoFiles, mono) {
5528
5594
  "B3",
5529
5595
  ["ci_script_depth", "default_branch_ci_depth"],
5530
5596
  () => evidence.push(
5531
- evidenceForRelative(mono.root, rootWorkflow, "ci_run", "CI workflow (monorepo root)")
5597
+ evidenceForRelative(
5598
+ mono.root,
5599
+ rootWorkflow,
5600
+ "ci_run",
5601
+ ciWorkflowCitationLabel(
5602
+ "CI workflow (monorepo root)",
5603
+ "read",
5604
+ workflowsRead,
5605
+ 1,
5606
+ unreadWorkflows
5607
+ )
5608
+ )
5532
5609
  )
5533
5610
  );
5534
5611
  }
@@ -5540,6 +5617,7 @@ function collectB3CiDisciplineEvidence(repoPath, repoFiles, mono) {
5540
5617
  CI_TYPECHECK_COMMAND_PATTERN,
5541
5618
  CI_BUILD_COMMAND_PATTERN
5542
5619
  ];
5620
+ const rootOnlyScriptsNote = rootOnlyPackageScriptsDisclosure(repoFiles, packageJson);
5543
5621
  const scriptDepth = ["test", "lint", "typecheck", "build"].filter(
5544
5622
  (s) => s === "test" ? hasCredibleTestScript(scripts) : scripts.has(s)
5545
5623
  ).length;
@@ -5585,7 +5663,8 @@ function collectB3CiDisciplineEvidence(repoPath, repoFiles, mono) {
5585
5663
  label: `monorepo-root CI command: ${["test", "lint", "type-check", "build"][index]}`,
5586
5664
  count: rootCategoryHits[index] ? 1 : 0
5587
5665
  })) : []
5588
- ]
5666
+ ],
5667
+ ...rootOnlyScriptsNote ? { condition: rootOnlyScriptsNote } : {}
5589
5668
  }
5590
5669
  ),
5591
5670
  metric(
@@ -6018,7 +6097,7 @@ var HEAVY_TEST_DEPENDENCY_NAME_PATTERN = /^(?:(?:jest|mocha|ava|tape|jasmine|kar
6018
6097
  var TIMING_SAFE_COMPARE_PATTERN = /\btiming[-_]?safe[-_]?(?:equal|compare)\b|crypto\.timingSafeEqual\s*\(/i;
6019
6098
  var CANONICAL_SERIALIZE_PATTERN = /\bcanonicalize\s*\(|\bcanonicalJson\b|\bstableStringify\s*\(|json-stable-stringify|safe-stable-stringify|\bsortKeys\s*\(/i;
6020
6099
  var SIGN_OR_HMAC_CALL_PATTERN = /\bcreateHmac\s*\(|\bcreateSign\s*\(|\.sign\s*\(/;
6021
- var INSECURE_SECRET_COMPARE_LINE_PATTERN = /\b\w*(?:hmac|signature|\bmac|digest)\w*\s*(===|!==)\s*(?!['"`]|undefined\b|null\b)([\w.]+(?:\s*[-+]\s*\d+)?)/i;
6100
+ var INSECURE_SECRET_COMPARE_LINE_PATTERN = /\b\w*(?:hmac|signature|\bmac)\w*\s*(===|!==)\s*(?!['"`]|undefined\b|null\b)([\w.]+(?:\s*[-+]\s*\d+)?)/i;
6022
6101
  var DEFAULT_SECRET_SENTINEL_COMPARE_LINE_PATTERN = /\b(?:secret|token|password|apiKey)\w*\s*(?:===|!==|==|!=)\s*[\w.]*default(?:Secret|Token|Password|ApiKey)\b/i;
6023
6102
  var NUMERIC_SHAPED_OPERAND_PATTERN = /^-?\d+$|\.(?:length|len|size|count)\b|(?:length|index|idx|offset|count|size|len)$/i;
6024
6103
  function lineHasInsecureSecretCompare(line, useV39Detectors = false) {
@@ -6412,6 +6491,81 @@ var JS_TEST_ASSERTION_PATTERN = /(expect\(|assert\.|should\.|toEqual\(|toBe\(|as
6412
6491
  var CPP_TEST_ASSERTION_PATTERN = /\bEXPECT_|ASSERT_EQ\b|ASSERT_TRUE\b|ASSERT_FALSE\b|\bREQUIRE\s*\(|\bCHECK\s*\(|\bTEST\s*\(|\bTEST_F\s*\(|\bTEST_CASE\s*\(|\bSECTION\s*\(/;
6413
6492
  var MULTI_ECOSYSTEM_TEST_ASSERTION_PATTERN = /\.assert[A-Z_]\w*\s*\(|\bassert[A-Z]\w*\s*\(|\bpytest\.raises\b|\bself\.fail\s*\(|\bt\.(?:Error|Errorf|Fatal|Fatalf|Fail|FailNow)\b|\brequire\.[A-Z]\w*\s*\(|\b(?:debug_)?assert(?:_eq|_ne)?!\s*\(|\bassert_\w+\b|\$this->assert\w+\s*\(/;
6414
6493
  var SUITE_LEVEL_SKIP_PATTERN = /\b(?:describe|suite|context)\.skip\s*\(/;
6494
+ function hasLiveAvaAssertion(contents) {
6495
+ const uncommented = stripJavaScriptComments(contents);
6496
+ const imports = [...uncommented.matchAll(/\bimport\s+([A-Za-z_$][\w$]*)\s+from\s*['"]ava['"]|\b(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*require\s*\(\s*['"]ava['"]\s*\)/g)];
6497
+ if (!imports.length) return false;
6498
+ let quote = "";
6499
+ let escaped = false;
6500
+ const characters = uncommented.split("");
6501
+ for (let i = 0; i < characters.length; i += 1) {
6502
+ const ch = characters[i];
6503
+ if (quote) {
6504
+ characters[i] = ch === "\n" ? "\n" : " ";
6505
+ if (escaped) escaped = false;
6506
+ else if (ch === "\\") escaped = true;
6507
+ else if (ch === quote) quote = "";
6508
+ } else if (ch === "'" || ch === '"' || ch === "`") {
6509
+ quote = ch;
6510
+ characters[i] = " ";
6511
+ }
6512
+ }
6513
+ const code = characters.join("");
6514
+ const imported = imports.find((candidate) => code[candidate.index] === uncommented[candidate.index]);
6515
+ const runner = imported?.[1] ?? imported?.[2];
6516
+ if (!runner) return false;
6517
+ const escape = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
6518
+ const calls = new RegExp(`\\b${escape(runner)}((?:\\.\\w+)*)\\s*\\(`, "g");
6519
+ const closeAt = (open, left, right) => {
6520
+ let depth = 1;
6521
+ for (let i = open + 1; i < code.length; i += 1) {
6522
+ if (code[i] === left) depth += 1;
6523
+ else if (code[i] === right && --depth === 0) return i;
6524
+ }
6525
+ return -1;
6526
+ };
6527
+ for (const call of code.matchAll(calls)) {
6528
+ const modifiers = call[1].split(".").filter(Boolean);
6529
+ if (modifiers.some((modifier) => !["serial", "only", "failing"].includes(modifier))) continue;
6530
+ const open = call.index + call[0].length - 1;
6531
+ const close = closeAt(open, "(", ")");
6532
+ if (close < 0) continue;
6533
+ const args = code.slice(open + 1, close);
6534
+ const callback = /(?:\basync\s+)?(?:\(\s*([A-Za-z_$][\w$]*)\s*\)|(?<![\w$])([A-Za-z_$][\w$]*))\s*=>|\bfunction(?:\s+\w+)?\s*\(\s*([A-Za-z_$][\w$]*)\s*\)/.exec(args);
6535
+ const parameter = callback?.[1] ?? callback?.[2] ?? callback?.[3];
6536
+ if (!callback || !parameter) continue;
6537
+ let start = open + 1 + callback.index + callback[0].length;
6538
+ while (/\s/.test(code[start] ?? "") && start < close) start += 1;
6539
+ const end = code[start] === "{" ? closeAt(start, "{", "}") : close;
6540
+ if (end < 0 || end > close) continue;
6541
+ const assertion = new RegExp(`\\b${escape(parameter)}\\.(?:assert|pass|fail|truthy|falsy|true|false|is|not|deepEqual|notDeepEqual|throws|throwsAsync|notThrows|notThrowsAsync|regex|notRegex|snapshot|like)\\s*\\(`);
6542
+ const body = code.slice(start, end);
6543
+ const active = body.split("");
6544
+ let maskedThrough = -1;
6545
+ for (const nested of body.matchAll(/=>\s*|\bfunction(?:\s+\w+)?\s*\([^)]*\)\s*/g)) {
6546
+ if (nested.index < maskedThrough) continue;
6547
+ const begin = nested.index + nested[0].length;
6548
+ let stop = begin;
6549
+ if (body[begin] === "{") {
6550
+ stop = closeAt(start + begin, "{", "}") - start + 1;
6551
+ } else {
6552
+ let depth = 0;
6553
+ while (stop < body.length) {
6554
+ const ch = body[stop];
6555
+ if (depth === 0 && /[;,)]/.test(ch)) break;
6556
+ if (ch === "(" || ch === "[") depth += 1;
6557
+ else if (ch === ")" || ch === "]") depth -= 1;
6558
+ stop += 1;
6559
+ }
6560
+ }
6561
+ if (stop <= begin) continue;
6562
+ for (let i = nested.index; i < Math.min(stop, active.length); i += 1) active[i] = " ";
6563
+ maskedThrough = stop;
6564
+ }
6565
+ if (assertion.test(active.join(""))) return true;
6566
+ }
6567
+ return false;
6568
+ }
6415
6569
  function measureNonHollowTestShare(repoPath, files, useV17Detectors = false) {
6416
6570
  let nonHollowCount = 0;
6417
6571
  let ratedCount = 0;
@@ -6419,7 +6573,7 @@ function measureNonHollowTestShare(repoPath, files, useV17Detectors = false) {
6419
6573
  const fullPath = join(repoPath, file);
6420
6574
  if (!isRegularFile(fullPath)) continue;
6421
6575
  const contents = readRepoText(fullPath, "utf8");
6422
- const nonHollow = (JS_TEST_ASSERTION_PATTERN.test(contents) || CPP_TEST_ASSERTION_PATTERN.test(contents) || MULTI_ECOSYSTEM_TEST_ASSERTION_PATTERN.test(contents)) && !SUITE_LEVEL_SKIP_PATTERN.test(contents);
6576
+ const nonHollow = (JS_TEST_ASSERTION_PATTERN.test(contents) || CPP_TEST_ASSERTION_PATTERN.test(contents) || MULTI_ECOSYSTEM_TEST_ASSERTION_PATTERN.test(contents) || hasLiveAvaAssertion(contents)) && !SUITE_LEVEL_SKIP_PATTERN.test(contents);
6423
6577
  if (nonHollow) {
6424
6578
  nonHollowCount += 1;
6425
6579
  ratedCount += 1;
@@ -8057,8 +8211,9 @@ var RACK_ENTRYPOINT_FILE_PATTERN = /(^|\/)(?:config\.ru|(?:main|server|app|start
8057
8211
  var SERVER_ENTRYPOINT_PATTERN = /\bapp\.listen\s*\(|\bserver\.listen\s*\(\s*(?:PORT|port|\d+)|http\.ListenAndServe\s*\(|http\.ListenAndServeTLS\s*\(|axum::Server(?:::|\.)|actix_web::HttpServer(?:::|\.)|uvicorn\.run\s*\(/;
8058
8212
  var V20_DIRECT_HTTP_SERVER_PATTERN = /\b(?:http|https)\.createServer\s*\([\s\S]{0,1500}?\)\.listen\s*\(\s*(?:PORT|port|\d+)/;
8059
8213
  var HEALTH_ROUTE_FUNCTIONS_DIR_PATTERN = /(^|\/)functions\/.*\.(?:ts|tsx|js|jsx|py|go|rs|java|rb|cpp|cc|cxx|c|h|hpp|kt|swift|php)$/;
8214
+ var HEALTH_ROUTE_ENTRYPOINT_HOME_PATTERN = /^(?:(?:server|index|app|main)\.(?:ts|tsx|js|jsx|mjs|cjs)|(?:server|backend|api)\/.*\.(?:ts|tsx|js|jsx|mjs|cjs|py|go|rs|java|rb|php))$/;
8060
8215
  var V20_HEALTH_OR_READINESS_ROUTE_PATTERN = /["'`](?:[\w${}./-]{0,60}\/[_-]?(?:(?:health|ready|live)z?|readiness|liveness|up)(?=["'`/])|(?:healthz|readiness|liveness)(?=["'`]))|@Get\s*\(\s*(["'`])health\1\s*\)/i;
8061
- var EXPRESS_ERROR_MIDDLEWARE_PATTERN = /\(\s*(?:_?err|_?error)(?:\s*:\s*(?:[^,()<]|<[^<>]*>)*)?\s*,\s*(?:req|request)(?:\s*:\s*(?:[^,()<]|<[^<>]*>)*)?\s*,\s*(?:res|response)(?:\s*:\s*(?:[^,()<]|<[^<>]*>)*)?\s*,\s*_?next(?:\s*:\s*(?:[^,()<]|<[^<>]*>)*)?\s*\)\s*(?:=>|\{)/i;
8216
+ var EXPRESS_ERROR_MIDDLEWARE_PATTERN = /\(\s*(?:_?err|_?error)(?:\s*:\s*(?:[^,()<]|<[^<>]*>)*)?\s*,\s*_?(?:req|request)(?:\s*:\s*(?:[^,()<]|<[^<>]*>)*)?\s*,\s*_?(?:res|response)(?:\s*:\s*(?:[^,()<]|<[^<>]*>)*)?\s*,\s*_?next(?:\s*:\s*(?:[^,()<]|<[^<>]*>)*)?\s*,?\s*\)\s*(?:=>|\{)/i;
8062
8217
  var EXPRESS_MIDDLEWARE_REACHABLE_PATTERN = /\.use\s*\(|\bmodule\.exports\b|\bexport\s+(?:default\b|function\b|const\b|class\b)/;
8063
8218
  var ERROR_BOUNDARY_FILENAME_PATTERN = /(^|\/)(?:error-boundary|error)\.(?:tsx|jsx|ts|js)$/;
8064
8219
  var RACK_SERVER_ENTRYPOINT_PATTERN = /Rack::(?:Server|Handler(?:::\w+)?)\.(?:start|run)\s*\(/;
@@ -8243,6 +8398,36 @@ function isV24IgnoredScanFile(file) {
8243
8398
  function findRootPackageJson(repoFiles) {
8244
8399
  return repoFiles.includes("package.json") ? "package.json" : null;
8245
8400
  }
8401
+ function ciWorkflowCitationLabel(baseLabel, verb, considered, cited, unread) {
8402
+ const unreadTotal = [...unread.values()].reduce((sum, count) => sum + count, 0);
8403
+ if (considered <= cited && unreadTotal === 0) return baseLabel;
8404
+ const parts = [
8405
+ `${considered} workflow file${considered === 1 ? "" : "s"} ${verb}`,
8406
+ `${cited} cited`
8407
+ ];
8408
+ if (unreadTotal > 0) {
8409
+ const reasons = [...unread.keys()].sort().join(", ");
8410
+ parts.push(`${unreadTotal} not read (${reasons})`);
8411
+ }
8412
+ return `${baseLabel} (${parts.join("; ")})`;
8413
+ }
8414
+ function unreadCiWorkflowReasons(includes) {
8415
+ const unread = /* @__PURE__ */ new Map();
8416
+ for (const { path, reasons } of withheldRepoPaths()) {
8417
+ if (!isCiWorkflow(path) || !includes(path)) continue;
8418
+ const reason = [...reasons].sort()[0];
8419
+ if (reason !== void 0) unread.set(reason, (unread.get(reason) ?? 0) + 1);
8420
+ }
8421
+ return unread;
8422
+ }
8423
+ function rootOnlyPackageScriptsDisclosure(repoFiles, rootPackageJson) {
8424
+ const others = repoFiles.filter(
8425
+ (file) => file !== rootPackageJson && /(^|\/)package\.json$/.test(file) && isAuthoredProductionPath(file)
8426
+ ).length;
8427
+ if (others === 0) return null;
8428
+ const present = `${others}${rootPackageJson ? " other" : ""} package.json file${others === 1 ? "" : "s"} present`;
8429
+ return `${rootPackageJson ? "" : "no root package.json found; "}package scripts for this metric are read from the root package.json only; ${present}`;
8430
+ }
8246
8431
  function isRegularFile(path) {
8247
8432
  try {
8248
8433
  return lstatSync(path).isFile();
@@ -5,7 +5,7 @@ import {
5
5
  renderWitanBadgeSvg,
6
6
  renderWitanHtmlReport,
7
7
  runCejelScan
8
- } from "./chunk-FA72HEWJ.js";
8
+ } from "./chunk-4YK23CST.js";
9
9
  import {
10
10
  ZodFirstPartyTypeKind,
11
11
  ZodOptional,
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import { createRequire as __cejelCreateRequire } from 'node:module';
3
3
  const require = __cejelCreateRequire(import.meta.url);
4
4
  import {
5
5
  serveCejelMcpOverStdio
6
- } from "./chunk-KAMWXGY7.js";
6
+ } from "./chunk-HC2WASRS.js";
7
7
  import {
8
8
  CALLER_CONTEXT_PRODUCT_IDENTITY_NOTICE,
9
9
  CERTIFICATE_GLOSSARY,
@@ -29,7 +29,7 @@ import {
29
29
  runCejelScan,
30
30
  serializeWitanReport,
31
31
  verifyWitanAttestationBinding
32
- } from "./chunk-FA72HEWJ.js";
32
+ } from "./chunk-4YK23CST.js";
33
33
  import "./chunk-63XQDYQ5.js";
34
34
  import {
35
35
  external_exports
@@ -42,7 +42,7 @@ import {
42
42
  init_esm_shims();
43
43
  import { createHash as createHash3 } from "crypto";
44
44
  import { existsSync, mkdirSync, readFileSync, realpathSync, writeFileSync } from "fs";
45
- import { dirname, join, resolve } from "path";
45
+ import { dirname, join, resolve as resolve2 } from "path";
46
46
  import { fileURLToPath, pathToFileURL } from "url";
47
47
 
48
48
  // src/issuance/index.ts
@@ -541,6 +541,43 @@ function renderGitLabCodeQualityFooter(result) {
541
541
  `;
542
542
  }
543
543
 
544
+ // src/npx-version-guard.ts
545
+ init_esm_shims();
546
+ import { delimiter, resolve } from "path";
547
+ var EXACT_VERSION_PATTERN = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
548
+ function npxVersionMismatchWarning(context) {
549
+ const { env, packageName, runningVersion, runningPath } = context;
550
+ if (env.npm_lifecycle_event !== "npx") return void 0;
551
+ if (env.npm_config_call) return void 0;
552
+ const pinned = exactPackageSpecVersion(env.npm_config_package, packageName);
553
+ if (pinned !== void 0) {
554
+ if (pinned === runningVersion) return void 0;
555
+ return `warning: npx was asked for ${packageName}@${pinned}, but cejel ${runningVersion} is running from ${runningPath}. Inside a ${packageName} checkout, npx can run the cejel on PATH; run it from another directory (#436).`;
556
+ }
557
+ const requested = env.npm_package_version;
558
+ if (env.npm_package_name !== packageName || !requested) return void 0;
559
+ if (!resolvedToLocalTree(env, context.cwd)) return void 0;
560
+ if (requested === runningVersion) return void 0;
561
+ const checkout = env.npm_config_local_prefix || context.cwd;
562
+ return `warning: npx resolved ${packageName} to the ${requested} checkout at ${checkout} and ran the cejel on PATH instead: cejel ${runningVersion} from ${runningPath}. Run npx from another directory to get the version you asked for (#436).`;
563
+ }
564
+ function exactPackageSpecVersion(packageSpecs, packageName) {
565
+ if (!packageSpecs) return void 0;
566
+ const prefix = `${packageName}@`;
567
+ for (const spec of packageSpecs.split(/\n+/)) {
568
+ const trimmed = spec.trim();
569
+ if (!trimmed.startsWith(prefix)) continue;
570
+ const version = trimmed.slice(prefix.length);
571
+ if (EXACT_VERSION_PATTERN.test(version)) return version;
572
+ }
573
+ return void 0;
574
+ }
575
+ function resolvedToLocalTree(env, cwd) {
576
+ const pathKey = Object.keys(env).find((key) => /^path$/i.test(key) && env[key]);
577
+ const first = pathKey ? env[pathKey]?.split(delimiter)[0] : void 0;
578
+ return first !== void 0 && first === resolve(cwd, "node_modules", ".bin");
579
+ }
580
+
544
581
  // src/terminal.ts
545
582
  init_esm_shims();
546
583
  function renderMinScoreAbstentionFailure(summary, minScore) {
@@ -862,8 +899,29 @@ async function main() {
862
899
  process.exitCode = exitCode;
863
900
  }
864
901
  async function runWitanFreeCli(args) {
902
+ warnIfNpxRanAnotherVersion();
865
903
  return runWitanCli(args);
866
904
  }
905
+ function warnIfNpxRanAnotherVersion() {
906
+ const warning = npxVersionMismatchWarning({
907
+ env: process.env,
908
+ cwd: process.cwd(),
909
+ packageName: NPX_PACKAGE_NAME,
910
+ runningVersion: cliVersion(),
911
+ runningPath: runningEntryPath()
912
+ });
913
+ if (warning) process.stderr.write(`${warning}
914
+ `);
915
+ }
916
+ function runningEntryPath() {
917
+ const invokedPath = process.argv[1];
918
+ if (!invokedPath) return process.execPath;
919
+ try {
920
+ return realpathSync(invokedPath);
921
+ } catch {
922
+ return invokedPath;
923
+ }
924
+ }
867
925
  async function runWitanV22CalibrationCli(args) {
868
926
  return runWitanCli(args, WITAN_RUBRIC_VERSION_V22);
869
927
  }
@@ -1039,8 +1097,8 @@ function parseExportArgs(args) {
1039
1097
  return {
1040
1098
  command: "export",
1041
1099
  format,
1042
- reportPath: resolve(reportPath),
1043
- outPath: resolve(outPath)
1100
+ reportPath: resolve2(reportPath),
1101
+ outPath: resolve2(outPath)
1044
1102
  };
1045
1103
  }
1046
1104
  function runExport(invocation) {
@@ -1074,8 +1132,8 @@ function parseVerifyArgs(args) {
1074
1132
  if (arg === "--signers" || arg === "--revocations") {
1075
1133
  const value = args[index + 1];
1076
1134
  if (!value) throw new Error(`Missing value for ${arg}`);
1077
- if (arg === "--signers") signersPath = resolve(value);
1078
- else revocationsPath = resolve(value);
1135
+ if (arg === "--signers") signersPath = resolve2(value);
1136
+ else revocationsPath = resolve2(value);
1079
1137
  index += 1;
1080
1138
  continue;
1081
1139
  }
@@ -1087,10 +1145,10 @@ function parseVerifyArgs(args) {
1087
1145
  if (!reportPath || !attestationPath) throw new Error(VERIFY_USAGE());
1088
1146
  return {
1089
1147
  command: "verify",
1090
- reportPath: resolve(reportPath),
1091
- attestationPath: resolve(attestationPath),
1092
- ...issuancePath ? { issuancePath: resolve(issuancePath) } : {},
1093
- ...issuanceSignaturePath ? { issuanceSignaturePath: resolve(issuanceSignaturePath) } : {},
1148
+ reportPath: resolve2(reportPath),
1149
+ attestationPath: resolve2(attestationPath),
1150
+ ...issuancePath ? { issuancePath: resolve2(issuancePath) } : {},
1151
+ ...issuanceSignaturePath ? { issuanceSignaturePath: resolve2(issuanceSignaturePath) } : {},
1094
1152
  ...signersPath ? { signersPath } : {},
1095
1153
  ...revocationsPath ? { revocationsPath } : {}
1096
1154
  };
@@ -1116,15 +1174,15 @@ function parseIssueArgs(args) {
1116
1174
  if (arg === void 0) continue;
1117
1175
  switch (arg) {
1118
1176
  case "--report":
1119
- reportPath = resolve(takeValue(arg, index + 1));
1177
+ reportPath = resolve2(takeValue(arg, index + 1));
1120
1178
  index += 1;
1121
1179
  continue;
1122
1180
  case "--attestation":
1123
- attestationPath = resolve(takeValue(arg, index + 1));
1181
+ attestationPath = resolve2(takeValue(arg, index + 1));
1124
1182
  index += 1;
1125
1183
  continue;
1126
1184
  case "--key":
1127
- keyPath = resolve(takeValue(arg, index + 1));
1185
+ keyPath = resolve2(takeValue(arg, index + 1));
1128
1186
  index += 1;
1129
1187
  continue;
1130
1188
  case "--engagement-ref":
@@ -1133,7 +1191,7 @@ function parseIssueArgs(args) {
1133
1191
  continue;
1134
1192
  case "--out":
1135
1193
  case "--out-dir":
1136
- outDir = resolve(takeValue(arg, index + 1));
1194
+ outDir = resolve2(takeValue(arg, index + 1));
1137
1195
  index += 1;
1138
1196
  continue;
1139
1197
  case "--product-name":
@@ -1177,7 +1235,7 @@ function parseIssueArgs(args) {
1177
1235
  throw new Error("--product-name and --name cannot be used together");
1178
1236
  }
1179
1237
  return {
1180
- repoPath: resolve(repoPath ?? "."),
1238
+ repoPath: resolve2(repoPath ?? "."),
1181
1239
  reportPath,
1182
1240
  attestationPath,
1183
1241
  keyPath,
@@ -1530,7 +1588,7 @@ function parseArgs(args) {
1530
1588
  throw new Error("--product-name and --name cannot be used together");
1531
1589
  }
1532
1590
  return {
1533
- repoPath: resolve(repoPath ?? "."),
1591
+ repoPath: resolve2(repoPath ?? "."),
1534
1592
  outDir,
1535
1593
  ...minScore != null ? { minScore } : {},
1536
1594
  ...productName ? { productName } : {},
package/dist/mcp/index.js CHANGED
@@ -3,8 +3,8 @@ import { createRequire as __cejelCreateRequire } from 'node:module';
3
3
  const require = __cejelCreateRequire(import.meta.url);
4
4
  import {
5
5
  serveCejelMcpOverStdio
6
- } from "../chunk-KAMWXGY7.js";
7
- import "../chunk-FA72HEWJ.js";
6
+ } from "../chunk-HC2WASRS.js";
7
+ import "../chunk-4YK23CST.js";
8
8
  import "../chunk-63XQDYQ5.js";
9
9
  import "../chunk-FSMZV3Y6.js";
10
10
  import {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cejel/cejel",
3
- "version": "0.6.3",
3
+ "version": "0.6.4",
4
4
  "mcpName": "io.github.BargLabs/cejel",
5
5
  "private": false,
6
6
  "publishConfig": {