@cejel/cejel 0.1.10 → 0.2.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/README.md CHANGED
@@ -18,7 +18,10 @@ certificate + badge over all of them. See "Aggregate your scanners" below.
18
18
 
19
19
  > Dogfooded in production. Cejel is run continuously on Barg Labs' own multi-product
20
20
  > monorepo — the ten-product studio it was built inside — which it currently scores
21
- > 3.1/4.0 ("Conditional"). We score ourselves before asking you to score yourself.
21
+ > 3.3/4.0 on its rubric-native certificate. That transparency snapshot opts into prospective
22
+ > v18; the public CLI default remains calibrated v17. On the comparative board, our code sits
23
+ > outside the ranked population and receives no verdict band. We score ourselves before
24
+ > asking you to score yourself.
22
25
 
23
26
  ## Install
24
27
 
@@ -99,16 +102,17 @@ gh attestation verify ./cejel-Darwin-arm64 -R BargLabs/cejel
99
102
  This is cryptographically signed provenance. It is distinct from Apple Developer ID or
100
103
  Microsoft Authenticode code-signing.
101
104
 
102
- **Docker / OCI.** The same MCP server is published as a non-root, multi-platform image:
105
+ **Docker / OCI.** The current container release is `0.2.0` (container releases are
106
+ versioned independently from npm-only patches):
103
107
 
104
108
  ```bash
105
- docker run --rm -i -v "$PWD:/workspace:ro" ghcr.io/barglabs/cejel:0.1.10
109
+ docker run --rm -i -v "$PWD:/workspace:ro" ghcr.io/barglabs/cejel:0.2.0
106
110
  ```
107
111
 
108
112
  The image defaults to `cejel-mcp` over stdio. To use the CLI instead:
109
113
 
110
114
  ```bash
111
- docker run --rm -v "$PWD:/workspace:ro" --entrypoint cejel ghcr.io/barglabs/cejel:0.1.10 .
115
+ docker run --rm -v "$PWD:/workspace:ro" --entrypoint cejel ghcr.io/barglabs/cejel:0.2.0 .
112
116
  ```
113
117
 
114
118
  The OCI image carries an SBOM, maximum-mode build provenance, and a signed registry
@@ -4079,8 +4079,7 @@ var WITAN_RUBRIC_VERSION_V5 = "witan-rubric-v5-2026-07-18";
4079
4079
  var WITAN_RUBRIC_VERSION_V6 = "witan-rubric-v6-2026-07-21";
4080
4080
  var WITAN_RUBRIC_VERSION_V7 = "witan-rubric-v7-2026-07-21";
4081
4081
  var WITAN_RUBRIC_VERSION_V8 = "witan-rubric-v8-2026-07-21";
4082
- var WITAN_RUBRIC_VERSION_V9 = "witan-rubric-v9-2026-07-22";
4083
- var WITAN_RUBRIC_VERSION = WITAN_RUBRIC_VERSION_V9;
4082
+ var WITAN_RUBRIC_VERSION = "witan-rubric-v17-2026-07-24";
4084
4083
  var WITAN_TRADING_RUBRIC_VERSION_V0 = "witan-trading-rubric-v0-2026-07-01";
4085
4084
  var WITAN_CRITERION_IDS = [
4086
4085
  "A1",
@@ -4369,7 +4368,7 @@ var WitanAttestationStatementSchema = external_exports.object({
4369
4368
  var WITAN_NO_MEASUREMENT_REASON = "No free-core rubric criterion produced a measurable signal. Cejel abstains rather than publish a numeric zero for an entirely unmeasured repository.";
4370
4369
  var WITAN_AUTHENTICATED_A1_ABSENCE_SUMMARY = "Reviewable source is present, but the complete tracked inventory contains no concrete test file, configured test runner, CI test command, or coverage configuration.";
4371
4370
  function isWitanNoMeasurementAbstention(report) {
4372
- return report.verdict === "insufficient_source" && report.insufficientSourceReason === WITAN_NO_MEASUREMENT_REASON && report.criteria.every(
4371
+ return report.verdict === "insufficient_source" && report.insufficientSourceReason.startsWith(WITAN_NO_MEASUREMENT_REASON) && report.criteria.every(
4373
4372
  ({ status }) => status === "not_applicable" || status === "insufficient_data"
4374
4373
  );
4375
4374
  }
@@ -5078,7 +5077,7 @@ function stripBom(text) {
5078
5077
  }
5079
5078
 
5080
5079
  // src/witan/rubric-version.ts
5081
- var WITAN_RUBRIC_VERSION_V92 = "witan-rubric-v9-2026-07-22";
5080
+ var WITAN_RUBRIC_VERSION_V9 = "witan-rubric-v9-2026-07-22";
5082
5081
  var WITAN_RUBRIC_VERSION_V10 = "witan-rubric-v10-2026-07-23";
5083
5082
  var WITAN_RUBRIC_VERSION_V11 = "witan-rubric-v11-2026-07-23";
5084
5083
  var WITAN_RUBRIC_VERSION_V12 = "witan-rubric-v12-2026-07-23";
@@ -5087,8 +5086,12 @@ var WITAN_RUBRIC_VERSION_V14 = "witan-rubric-v14-2026-07-23";
5087
5086
  var WITAN_RUBRIC_VERSION_V15 = "witan-rubric-v15-2026-07-24";
5088
5087
  var WITAN_RUBRIC_VERSION_V16 = "witan-rubric-v16-2026-07-24";
5089
5088
  var WITAN_RUBRIC_VERSION_V17 = "witan-rubric-v17-2026-07-24";
5089
+ var WITAN_RUBRIC_VERSION_V18 = "witan-rubric-v18-prospective-2026-07-25";
5090
5090
 
5091
5091
  // src/witan/repo-signals.ts
5092
+ function usesV17DetectorClosure(rubricVersion) {
5093
+ return rubricVersion === WITAN_RUBRIC_VERSION_V17 || rubricVersion === WITAN_RUBRIC_VERSION_V18;
5094
+ }
5092
5095
  function buildWitanInputFromRepo(options) {
5093
5096
  assertRepoPathExists(options.repoPath);
5094
5097
  const generatedAt = options.generatedAt ?? (/* @__PURE__ */ new Date()).toISOString();
@@ -5097,26 +5100,27 @@ function buildWitanInputFromRepo(options) {
5097
5100
  const repoFiles = listRepoFiles(options.repoPath);
5098
5101
  const inventoryFiles = listRepoInventory(options.repoPath, repoFiles);
5099
5102
  const ignoredTargetReason = repoFiles.length === 0 ? explainIgnoredScanTarget(options.repoPath) : void 0;
5100
- const usesV17Detectors = rubricVersion === WITAN_RUBRIC_VERSION_V17;
5103
+ const usesV17Detectors = usesV17DetectorClosure(rubricVersion);
5104
+ const usesV18NativeRls = rubricVersion === WITAN_RUBRIC_VERSION_V18;
5101
5105
  const structuralArchetype = classifyRepoArchetype(inventoryFiles, rubricVersion);
5102
- const readableArchetype = 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 ? applyReadableSourceRepresentationGate(
5106
+ const readableArchetype = rubricVersion === WITAN_RUBRIC_VERSION_V13 || rubricVersion === WITAN_RUBRIC_VERSION_V14 || rubricVersion === WITAN_RUBRIC_VERSION_V15 || rubricVersion === WITAN_RUBRIC_VERSION_V16 || usesV17DetectorClosure(rubricVersion) ? applyReadableSourceRepresentationGate(
5103
5107
  options.repoPath,
5104
5108
  inventoryFiles,
5105
5109
  structuralArchetype,
5106
5110
  headSha,
5107
5111
  rubricVersion
5108
5112
  ) : structuralArchetype;
5109
- const gatedArchetype = rubricVersion === WITAN_RUBRIC_VERSION_V14 || rubricVersion === WITAN_RUBRIC_VERSION_V15 || rubricVersion === WITAN_RUBRIC_VERSION_V16 || rubricVersion === WITAN_RUBRIC_VERSION_V17 ? applySemanticSourceRepresentationGate(
5113
+ const gatedArchetype = rubricVersion === WITAN_RUBRIC_VERSION_V14 || rubricVersion === WITAN_RUBRIC_VERSION_V15 || rubricVersion === WITAN_RUBRIC_VERSION_V16 || usesV17DetectorClosure(rubricVersion) ? applySemanticSourceRepresentationGate(
5110
5114
  options.repoPath,
5111
5115
  inventoryFiles,
5112
5116
  readableArchetype,
5113
5117
  rubricVersion
5114
5118
  ) : readableArchetype;
5115
- const usesV8Detectors = rubricVersion === WITAN_RUBRIC_VERSION_V8 || rubricVersion === WITAN_RUBRIC_VERSION_V92 || 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;
5116
- const usesV33Detectors = rubricVersion === WITAN_RUBRIC_VERSION_V92 || 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;
5117
- const usesV36Detectors = 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;
5118
- const usesV39Detectors = 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;
5119
- const usesV47Detectors = rubricVersion === WITAN_RUBRIC_VERSION_V15 || rubricVersion === WITAN_RUBRIC_VERSION_V16 || rubricVersion === WITAN_RUBRIC_VERSION_V17;
5119
+ const usesV8Detectors = 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 || usesV17DetectorClosure(rubricVersion);
5120
+ const usesV33Detectors = 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 || usesV17DetectorClosure(rubricVersion);
5121
+ const usesV36Detectors = 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 || usesV17DetectorClosure(rubricVersion);
5122
+ const usesV39Detectors = 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 || usesV17DetectorClosure(rubricVersion);
5123
+ const usesV47Detectors = rubricVersion === WITAN_RUBRIC_VERSION_V15 || rubricVersion === WITAN_RUBRIC_VERSION_V16 || usesV17DetectorClosure(rubricVersion);
5120
5124
  const reviewableSourceProof = usesV17Detectors ? buildReviewableSourceProof(options.repoPath, inventoryFiles, headSha, rubricVersion) : void 0;
5121
5125
  const coreSignals = collectRepoSignals(
5122
5126
  options.repoPath,
@@ -5127,6 +5131,7 @@ function buildWitanInputFromRepo(options) {
5127
5131
  usesV36Detectors,
5128
5132
  usesV39Detectors,
5129
5133
  usesV47Detectors,
5134
+ usesV18NativeRls,
5130
5135
  reviewableSourceProof
5131
5136
  );
5132
5137
  const archetype = usesV17Detectors && reviewableSourceProof?.passes === true && isV17RescuableAbstention(gatedArchetype.abstentionKind) && coreSignals.some(isMeasuredCriterionSignal) ? {
@@ -5234,7 +5239,7 @@ var SOURCE_EXTENSION_PATTERN_V10 = new RegExp(
5234
5239
  "i"
5235
5240
  );
5236
5241
  function isRecognizedSourcePath(path, rubricVersion = WITAN_RUBRIC_VERSION) {
5237
- return (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 ? SOURCE_EXTENSION_PATTERN_V10 : SOURCE_EXTENSION_PATTERN).test(path);
5242
+ return (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 || usesV17DetectorClosure(rubricVersion) ? SOURCE_EXTENSION_PATTERN_V10 : SOURCE_EXTENSION_PATTERN).test(path);
5238
5243
  }
5239
5244
  var BUNDLED_BINARY_EXTENSION_PATTERN = /\.(vsix|zip|tgz|whl|exe|dmg|pkg|msi|jar|war|apk|ipa|dll|dylib|ttf|otf|woff2?|eot|eps)$/i;
5240
5245
  var DOCS_OR_MEDIA_EXTENSION_PATTERN = /\.(md|mdx|rst|png|jpe?g|gif|svg|webp|ico|pdf)$/i;
@@ -5250,6 +5255,7 @@ var SOURCE_DOMINANCE_RATIO_THRESHOLD_V8 = 0.2;
5250
5255
  var SOURCE_DOMINANCE_RATIO_THRESHOLD_V9 = 0.8;
5251
5256
  var SOURCE_DOMINANCE_RATIO_THRESHOLD_V10 = 0.5;
5252
5257
  var SOURCE_DOMINANCE_RATIO_THRESHOLD_V11 = 0.2;
5258
+ var V17_REVIEWABLE_SOURCE_RATABLE_SHARE_THRESHOLD = 0.2;
5253
5259
  var GENERATED_SOURCE_MINIMUM = 8;
5254
5260
  var GENERATED_SOURCE_RATIO_THRESHOLD = 0.8;
5255
5261
  var GENERATED_AUTHORED_MAXIMUM = 3;
@@ -5293,7 +5299,7 @@ function classifyRepoArchetype(repoFiles, rubricVersion = WITAN_RUBRIC_VERSION)
5293
5299
  insufficientSourceReason: `${catalogSourceFiles.length} of ${sourceFileCount} source-shaped file(s) are under independent solution, exercise, challenge, or algorithm catalog paths; only ${sourceFileCount - catalogSourceFiles.length} source-shaped file(s) remain outside that catalog. Cejel abstains because the repository does not expose one cohesive product implementation to score. ${INGEST_POINTER}`
5294
5300
  };
5295
5301
  }
5296
- if (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) {
5302
+ if (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 || usesV17DetectorClosure(rubricVersion)) {
5297
5303
  const authoredSourceFiles = sourceFiles.filter(isAuthoredProductionPath);
5298
5304
  const documentationFiles = repoFiles.filter(
5299
5305
  (file) => DOCS_OR_MEDIA_EXTENSION_PATTERN.test(file)
@@ -5311,7 +5317,7 @@ function classifyRepoArchetype(repoFiles, rubricVersion = WITAN_RUBRIC_VERSION)
5311
5317
  (file) => ARTIFACT_DOMINANCE_EXTENSION_PATTERN.test(file)
5312
5318
  );
5313
5319
  const materialFiles = authoredSourceFiles.length + artifactFiles.length;
5314
- if (artifactFiles.length >= 10 && (authoredSourceFiles.length <= 10 || rubricVersion === WITAN_RUBRIC_VERSION_V14 || rubricVersion === WITAN_RUBRIC_VERSION_V15 || rubricVersion === WITAN_RUBRIC_VERSION_V16 || rubricVersion === WITAN_RUBRIC_VERSION_V17) && materialFiles > 0 && authoredSourceFiles.length / materialFiles <= 0.1) {
5320
+ if (artifactFiles.length >= 10 && (authoredSourceFiles.length <= 10 || rubricVersion === WITAN_RUBRIC_VERSION_V14 || rubricVersion === WITAN_RUBRIC_VERSION_V15 || rubricVersion === WITAN_RUBRIC_VERSION_V16 || usesV17DetectorClosure(rubricVersion)) && materialFiles > 0 && authoredSourceFiles.length / materialFiles <= 0.1) {
5315
5321
  return {
5316
5322
  archetype: "binary_only",
5317
5323
  sourceFileCount,
@@ -5338,7 +5344,7 @@ function classifyRepoArchetype(repoFiles, rubricVersion = WITAN_RUBRIC_VERSION)
5338
5344
  const docsDistributionFiles = repoFiles.filter(
5339
5345
  (file) => DOCS_OR_MEDIA_EXTENSION_PATTERN.test(file) || DOC_DISTRIBUTION_COMPANION_PATTERN.test(file)
5340
5346
  );
5341
- if (docsFiles.length > 0 && (docsDistributionFiles.length === totalFileCount || (rubricVersion === WITAN_RUBRIC_VERSION_V92 || 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) && unrecognisedSourceFiles.length === 0)) {
5347
+ if (docsFiles.length > 0 && (docsDistributionFiles.length === totalFileCount || (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 || usesV17DetectorClosure(rubricVersion)) && unrecognisedSourceFiles.length === 0)) {
5342
5348
  return {
5343
5349
  archetype: "docs_only",
5344
5350
  sourceFileCount,
@@ -5457,6 +5463,23 @@ function isRepresentativeSourceText(contents) {
5457
5463
  function representativeSourceRank(rankKey, file) {
5458
5464
  return createHash2("sha256").update(`${rankKey}:${file}`).digest("hex");
5459
5465
  }
5466
+ function explainNoMeasurementSourceCoverage(repoPath, rubricVersion) {
5467
+ if (!usesV17DetectorClosure(rubricVersion)) return void 0;
5468
+ const repoFiles = listRepoFiles(repoPath);
5469
+ const inventoryFiles = listRepoInventory(repoPath, repoFiles);
5470
+ const proof = buildReviewableSourceProof(
5471
+ repoPath,
5472
+ inventoryFiles,
5473
+ readGitHead(repoPath),
5474
+ rubricVersion
5475
+ );
5476
+ if (proof.sourceShapedFileCount === 0) return void 0;
5477
+ const ratableShare = proof.eligibleSourceFileCount / proof.sourceShapedFileCount;
5478
+ if (ratableShare >= V17_REVIEWABLE_SOURCE_RATABLE_SHARE_THRESHOLD) return void 0;
5479
+ const ratablePct = (ratableShare * 100).toFixed(1);
5480
+ const thresholdPct = (V17_REVIEWABLE_SOURCE_RATABLE_SHARE_THRESHOLD * 100).toFixed(0);
5481
+ return `${WITAN_NO_MEASUREMENT_REASON} Source coverage: ${proof.eligibleSourceFileCount} of ${proof.sourceShapedFileCount} source-shaped files (${ratablePct}%) are criterion-ratable, below the ${thresholdPct}% reviewable-source threshold (${inventoryFiles.length} tracked files in total).`;
5482
+ }
5460
5483
  function buildReviewableSourceProof(repoPath, repoFiles, headSha, rubricVersion) {
5461
5484
  const sourceShapedFiles = repoFiles.filter(
5462
5485
  (path) => isRecognizedSourcePath(path, rubricVersion) || isUnrecognisedSourcePath(path, rubricVersion) || /\.ipynb$/i.test(path)
@@ -5481,7 +5504,7 @@ function buildReviewableSourceProof(repoPath, repoFiles, headSha, rubricVersion)
5481
5504
  sampledFileCount: sample.length,
5482
5505
  readableSampledFileCount: readablePaths.length,
5483
5506
  ...readablePaths[0] ? { firstReadablePath: readablePaths[0] } : {},
5484
- passes: eligibleSourceFiles.length > 0 && ratableShare >= 0.2 && readablePaths.length > 0 && (readableShare >= 0.75 || readablePaths.length >= 8)
5507
+ passes: eligibleSourceFiles.length > 0 && ratableShare >= V17_REVIEWABLE_SOURCE_RATABLE_SHARE_THRESHOLD && readablePaths.length > 0 && (readableShare >= 0.75 || readablePaths.length >= 8)
5485
5508
  };
5486
5509
  }
5487
5510
  function applyReadableSourceRepresentationGate(repoPath, repoFiles, classification, headSha, rubricVersion) {
@@ -5623,11 +5646,11 @@ function readRepresentativeSourceText(repoPath, file) {
5623
5646
  }
5624
5647
  }
5625
5648
  function sourceDominanceThreshold(rubricVersion) {
5626
- if (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) {
5649
+ if (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 || usesV17DetectorClosure(rubricVersion)) {
5627
5650
  return SOURCE_DOMINANCE_RATIO_THRESHOLD_V11;
5628
5651
  }
5629
5652
  if (rubricVersion === WITAN_RUBRIC_VERSION_V10) return SOURCE_DOMINANCE_RATIO_THRESHOLD_V10;
5630
- if (rubricVersion === WITAN_RUBRIC_VERSION_V92) return SOURCE_DOMINANCE_RATIO_THRESHOLD_V9;
5653
+ if (rubricVersion === WITAN_RUBRIC_VERSION_V9) return SOURCE_DOMINANCE_RATIO_THRESHOLD_V9;
5631
5654
  return SOURCE_DOMINANCE_RATIO_THRESHOLD_V8;
5632
5655
  }
5633
5656
  function collectUnrecognisedSourceFiles(repoFiles, rubricVersion) {
@@ -5637,7 +5660,7 @@ function isUnrecognisedSourcePath(file, rubricVersion = WITAN_RUBRIC_VERSION) {
5637
5660
  const base = basename(file);
5638
5661
  if (!/\.([a-zA-Z0-9_]+)$/.test(base)) return false;
5639
5662
  if (KNOWN_NON_SOURCE_EXTENSION_PATTERN.test(base)) return false;
5640
- if ((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) && V13_NON_SOURCE_EXTENSION_PATTERN.test(base)) {
5663
+ if ((rubricVersion === WITAN_RUBRIC_VERSION_V13 || rubricVersion === WITAN_RUBRIC_VERSION_V14 || rubricVersion === WITAN_RUBRIC_VERSION_V15 || rubricVersion === WITAN_RUBRIC_VERSION_V16 || usesV17DetectorClosure(rubricVersion)) && V13_NON_SOURCE_EXTENSION_PATTERN.test(base)) {
5641
5664
  return false;
5642
5665
  }
5643
5666
  if (DOCS_OR_MEDIA_EXTENSION_PATTERN.test(base)) return false;
@@ -5723,7 +5746,7 @@ function buildNotApplicableSignal(criterionId, reason) {
5723
5746
  notApplicable: true
5724
5747
  };
5725
5748
  }
5726
- function collectRepoSignals(repoPath, generatedAt, repoFiles, useV27Detectors, useV33Detectors, useV36Detectors, useV39Detectors, useV47Detectors, reviewableSourceProof) {
5749
+ function collectRepoSignals(repoPath, generatedAt, repoFiles, useV27Detectors, useV33Detectors, useV36Detectors, useV39Detectors, useV47Detectors, useV18NativeRls, reviewableSourceProof) {
5727
5750
  const signals = [];
5728
5751
  const mono = resolveMonorepoContext(repoPath);
5729
5752
  const a1Signal = collectA1TestIntegrityEvidence(
@@ -5741,7 +5764,8 @@ function collectRepoSignals(repoPath, generatedAt, repoFiles, useV27Detectors, u
5741
5764
  useV33Detectors,
5742
5765
  useV36Detectors,
5743
5766
  useV39Detectors,
5744
- useV47Detectors
5767
+ useV47Detectors,
5768
+ useV18NativeRls
5745
5769
  );
5746
5770
  const a3Signal = collectA3ProdReadinessEvidence(repoPath, repoFiles, useV27Detectors);
5747
5771
  const a4Signal = collectA4DependencyEvidence(
@@ -6033,7 +6057,7 @@ function buildA1AuthenticatedAbsenceSignal(repoPath, proof) {
6033
6057
  notes: `V17 authenticated absence: ${proof.eligibleSourceFileCount} criterion-ratable of ${proof.sourceShapedFileCount} source-shaped files; sampled ${proof.sampledFileCount}; ${proof.readableSampledFileCount} representative-text files.`
6034
6058
  };
6035
6059
  }
6036
- function collectA2IsolationEvidence(repoPath, repoFiles, useV27Detectors, useV33Detectors, useV36Detectors, useV39Detectors, useV47Detectors) {
6060
+ function collectA2IsolationEvidence(repoPath, repoFiles, useV27Detectors, useV33Detectors, useV36Detectors, useV39Detectors, useV47Detectors, useV18NativeRls) {
6037
6061
  const evidence = [];
6038
6062
  const findings = [];
6039
6063
  const gitignore = repoFiles.find((file) => basename(file) === ".gitignore");
@@ -6129,19 +6153,21 @@ function collectA2IsolationEvidence(repoPath, repoFiles, useV27Detectors, useV33
6129
6153
  evidence.push(evidenceForRelative(repoPath, dbLayerImportFile, "artifact", "DB client import"));
6130
6154
  }
6131
6155
  const v47RlsPolicyFiles = useV47Detectors ? findRlsPolicyFiles(repoPath, repoFiles) : [];
6132
- const v47TenantStorageFiles = useV47Detectors ? findTenantStoragePremiseFiles(repoPath, repoFiles) : [];
6156
+ const nativeRlsInventory = useV18NativeRls ? deriveRlsPolicyScopeInventory(repoPath, repoFiles) : null;
6157
+ const tenantWithoutRlsPremiseFiles = useV18NativeRls ? findTenantStoragePremiseFiles(repoPath, repoFiles) : [];
6158
+ const v47TenantStorageFiles = useV47Detectors && !useV18NativeRls ? findTenantStoragePremiseFiles(repoPath, repoFiles) : [];
6133
6159
  const rlsMigration = useV47Detectors ? v47RlsPolicyFiles[0] : migrationFiles.find((file) => fileContains(repoPath, file, RLS_PATTERN));
6134
6160
  const tenantScopePattern = useV39Detectors ? TENANT_SCOPE_PATTERN_V11 : useV36Detectors ? TENANT_SCOPE_PATTERN_V10 : TENANT_SCOPE_PATTERN;
6135
- const tenantScopedFile = useV47Detectors ? v47TenantStorageFiles[0] : migrationFiles.find((file) => fileContains(repoPath, file, tenantScopePattern));
6136
- const rlsPolicyCount = useV47Detectors ? v47RlsPolicyFiles.length : countPatternMatches(
6161
+ const tenantScopedFile = useV18NativeRls ? nativeRlsInventory?.storageFiles[0] : useV47Detectors ? v47TenantStorageFiles[0] : migrationFiles.find((file) => fileContains(repoPath, file, tenantScopePattern));
6162
+ const rlsPolicyCount = useV18NativeRls ? nativeRlsInventory?.policyCount ?? 0 : useV47Detectors ? v47RlsPolicyFiles.length : countPatternMatches(
6137
6163
  repoPath,
6138
6164
  migrationFiles,
6139
6165
  /create policy|enable row level security|force row level security/gi
6140
6166
  );
6141
- const tenantScopedMigrationFileCount = useV47Detectors ? v47TenantStorageFiles.length : countFilesContaining(repoPath, migrationFiles, tenantScopePattern);
6167
+ const tenantScopedMigrationFileCount = useV18NativeRls ? nativeRlsInventory?.storageFiles.length ?? 0 : useV47Detectors ? v47TenantStorageFiles.length : countFilesContaining(repoPath, migrationFiles, tenantScopePattern);
6142
6168
  const gitignoreEnvFile = gitignore && fileContains(repoPath, gitignore, /^\.env(\*|\b)|\.env\./m) ? gitignore : null;
6143
6169
  const envHandlingDepth = (envExamples.length > 0 ? 1 : 0) + (gitignoreEnvFile ? 1 : 0) + (countFilesContaining(repoPath, repoFiles.filter(isImplementationFile), ENV_READ_PATTERN) > 0 ? 1 : 0);
6144
- const isMultiTenant = tenantScopedMigrationFileCount > 0;
6170
+ const isMultiTenant = useV18NativeRls ? (nativeRlsInventory?.policyCount ?? 0) > 0 && (nativeRlsInventory?.scopeIdentifiers.length ?? 0) > 0 : tenantScopedMigrationFileCount > 0;
6145
6171
  if (gitignoreEnvFile) {
6146
6172
  evidence.push(
6147
6173
  evidenceForRelative(repoPath, gitignoreEnvFile, "secret_scan", ".env files are gitignored")
@@ -6157,7 +6183,12 @@ function collectA2IsolationEvidence(repoPath, repoFiles, useV27Detectors, useV33
6157
6183
  }
6158
6184
  if (tenantScopedFile) {
6159
6185
  evidence.push(
6160
- evidenceForRelative(repoPath, tenantScopedFile, "artifact", "Tenant scoping signal")
6186
+ evidenceForRelative(
6187
+ repoPath,
6188
+ tenantScopedFile,
6189
+ "artifact",
6190
+ useV18NativeRls ? `Repository-native RLS scope (${nativeRlsInventory?.scopeIdentifiers.join(", ")})` : "Tenant scoping signal"
6191
+ )
6161
6192
  );
6162
6193
  }
6163
6194
  if (committedSecret) {
@@ -6215,8 +6246,9 @@ function collectA2IsolationEvidence(repoPath, repoFiles, useV27Detectors, useV33
6215
6246
  evidence: historySecretScan.envPathEvidence
6216
6247
  });
6217
6248
  }
6218
- if (isMultiTenant && rlsPolicyCount === 0) {
6219
- const gapEvidence = rlsMigration ?? tenantScopedFile;
6249
+ const hasTenantWithoutRlsGap = rlsPolicyCount === 0 && (useV18NativeRls ? tenantWithoutRlsPremiseFiles.length > 0 : isMultiTenant);
6250
+ if (hasTenantWithoutRlsGap) {
6251
+ const gapEvidence = rlsMigration ?? tenantScopedFile ?? tenantWithoutRlsPremiseFiles[0];
6220
6252
  if (gapEvidence) {
6221
6253
  findings.push({
6222
6254
  severity: "warning",
@@ -6259,20 +6291,20 @@ function collectA2IsolationEvidence(repoPath, repoFiles, useV27Detectors, useV33
6259
6291
  "rls_policy_count",
6260
6292
  "RLS policy count",
6261
6293
  rlsPolicyCount,
6262
- Math.max(tenantScopedMigrationFileCount * 3, 3),
6294
+ useV18NativeRls ? Math.max(tenantScopedMigrationFileCount, 1) : Math.max(tenantScopedMigrationFileCount * 3, 3),
6263
6295
  0.4,
6264
6296
  "policies",
6265
- "Counts static row-level-security enables, forced-RLS statements, and policy definitions.",
6297
+ useV18NativeRls ? "Counts CREATE POLICY definitions with repository-native USING/WITH CHECK clauses against the repository-native scoped data-layer surface." : "Counts static row-level-security enables, forced-RLS statements, and policy definitions.",
6266
6298
  "saturating_count"
6267
6299
  ),
6268
6300
  metric(
6269
6301
  "tenant_scope_ratio",
6270
6302
  "Tenant-scoped schema ratio",
6271
- countFilesContaining(repoPath, migrationFiles, tenantScopePattern),
6303
+ useV18NativeRls ? tenantScopedMigrationFileCount : countFilesContaining(repoPath, migrationFiles, tenantScopePattern),
6272
6304
  Math.max(migrationFiles.length, 1),
6273
6305
  0.25,
6274
6306
  "ratio",
6275
- "Measures tenant/studio/workspace scoping evidence across data-layer files."
6307
+ useV18NativeRls ? `Measures repository-native RLS scope identifiers (${nativeRlsInventory?.scopeIdentifiers.join(", ")}) across data-layer files.` : "Measures tenant/studio/workspace scoping evidence across data-layer files."
6276
6308
  )
6277
6309
  ] : [];
6278
6310
  const cryptoMetrics = cryptoHygiene.hasSurface ? [
@@ -6291,7 +6323,7 @@ function collectA2IsolationEvidence(repoPath, repoFiles, useV27Detectors, useV33
6291
6323
  positiveEvidence: evidence,
6292
6324
  findings,
6293
6325
  metrics: [...baseMetrics, ...isolationMetrics, ...cryptoMetrics],
6294
- notes: "History secret scanning covers all reachable git history for credential-pattern paths unless the explicit credential-blob safety valve is reported."
6326
+ notes: useV18NativeRls ? "History secret scanning covers all reachable git history for credential-pattern paths unless the explicit credential-blob safety valve is reported. Positive multi-tenancy credit is derived only from this repository\u2019s own CREATE POLICY USING/WITH CHECK clauses; no fixed tenant-token vocabulary can create isolation credit. A conservative schema premise is retained only to fail closed when a tenant-shaped schema has zero RLS policies." : "History secret scanning covers all reachable git history for credential-pattern paths unless the explicit credential-blob safety valve is reported."
6295
6327
  };
6296
6328
  }
6297
6329
  function collectCryptoHygieneEvidence(repoPath, implFiles, useV39Detectors = false) {
@@ -7187,7 +7219,7 @@ var TEST_DIRECTORY_SOURCE_PATTERN_V17 = new RegExp(
7187
7219
  "i"
7188
7220
  );
7189
7221
  function isTestFile(file, rubricVersion = WITAN_RUBRIC_VERSION) {
7190
- return rubricVersion === WITAN_RUBRIC_VERSION_V17 && (TEST_DIRECTORY_SOURCE_PATTERN_V17.test(file) || /\.tftest\.hcl$/i.test(file) || /\.bats$/i.test(file) || /(^|\/)test[^/]*\.m$/i.test(file) || /_test\.m$/i.test(file)) || TEST_DIRECTORY_SOURCE_PATTERN.test(file) || // AVA's default discovery includes test.js and test-*.js at the scanned package root.
7222
+ return usesV17DetectorClosure(rubricVersion) && (TEST_DIRECTORY_SOURCE_PATTERN_V17.test(file) || /\.tftest\.hcl$/i.test(file) || /\.bats$/i.test(file) || /(^|\/)test[^/]*\.m$/i.test(file) || /_test\.m$/i.test(file)) || TEST_DIRECTORY_SOURCE_PATTERN.test(file) || // AVA's default discovery includes test.js and test-*.js at the scanned package root.
7191
7223
  // Keep this root-anchored: nested files need an existing test-directory/suffix convention.
7192
7224
  /^test(?:-[^/]+)?\.[cm]?[jt]sx?$/.test(file) || /\.(test|spec)\.[cm]?[jt]sx?$/.test(file) || /(^|\/)test_.*\.py$/.test(file) || /_test\.go$/.test(file) || /(^|\/)test_.*\.(cpp|cc|cxx)$/.test(file) || /_(test|tests)\.(cpp|cc|cxx)$/.test(file) || /Tests?\.(java|kt)$/.test(file) || /(_test|_spec)\.(rs|rb|php|swift|kt)$/.test(file);
7193
7225
  }
@@ -7858,6 +7890,138 @@ function findRlsPolicyFiles(repoPath, repoFiles) {
7858
7890
  )
7859
7891
  );
7860
7892
  }
7893
+ var RLS_CLAUSE_SQL_WORDS = /* @__PURE__ */ new Set([
7894
+ "all",
7895
+ "and",
7896
+ "any",
7897
+ "as",
7898
+ "asc",
7899
+ "between",
7900
+ "by",
7901
+ "case",
7902
+ "cast",
7903
+ "current",
7904
+ "desc",
7905
+ "distinct",
7906
+ "else",
7907
+ "end",
7908
+ "exists",
7909
+ "false",
7910
+ "from",
7911
+ "in",
7912
+ "is",
7913
+ "join",
7914
+ "like",
7915
+ "limit",
7916
+ "not",
7917
+ "null",
7918
+ "on",
7919
+ "or",
7920
+ "order",
7921
+ "select",
7922
+ "then",
7923
+ "text",
7924
+ "true",
7925
+ "uuid",
7926
+ "varchar",
7927
+ "when",
7928
+ "where"
7929
+ ]);
7930
+ function extractBalancedSqlClause(statement, keyword) {
7931
+ const clauses = [];
7932
+ const keywordPattern = keyword === "using" ? /\busing\s*\(/gi : /\bwith\s+check\s*\(/gi;
7933
+ for (const match of statement.matchAll(keywordPattern)) {
7934
+ const openingParen = (match.index ?? 0) + match[0].lastIndexOf("(");
7935
+ let depth = 0;
7936
+ let quote = null;
7937
+ for (let index = openingParen; index < statement.length; index += 1) {
7938
+ const character = statement[index];
7939
+ if (quote) {
7940
+ if (character === quote && statement[index - 1] !== "\\") quote = null;
7941
+ continue;
7942
+ }
7943
+ if (character === "'" || character === '"') {
7944
+ quote = character;
7945
+ } else if (character === "(") {
7946
+ depth += 1;
7947
+ } else if (character === ")") {
7948
+ depth -= 1;
7949
+ if (depth === 0) {
7950
+ clauses.push(statement.slice(openingParen + 1, index));
7951
+ break;
7952
+ }
7953
+ }
7954
+ }
7955
+ }
7956
+ return clauses;
7957
+ }
7958
+ function extractRlsScopeIdentifiers(clause) {
7959
+ const scrubbed = clause.replace(/'(?:''|[^'])*'/g, " ").replace(/"(?:""|[^"])*"/g, " ");
7960
+ const identifiers = /* @__PURE__ */ new Set();
7961
+ const identifierPattern = /\b[A-Za-z_][A-Za-z0-9_$]*(?:\.[A-Za-z_][A-Za-z0-9_$]*)*\b/g;
7962
+ for (const match of scrubbed.matchAll(identifierPattern)) {
7963
+ const token = match[0];
7964
+ const segments = token.split(".").map((segment) => segment.toLowerCase());
7965
+ const lastSegment = segments.at(-1);
7966
+ if (!lastSegment || lastSegment.length < 2 || RLS_CLAUSE_SQL_WORDS.has(lastSegment)) continue;
7967
+ if (["app", "auth", "jwt", "request", "session"].includes(segments[0] ?? "")) continue;
7968
+ const remainder = scrubbed.slice((match.index ?? 0) + token.length);
7969
+ if (/^\s*\(/.test(remainder)) continue;
7970
+ if (["auth", "current_setting", "jwt", "pg_catalog", "public", "uid"].includes(lastSegment)) {
7971
+ continue;
7972
+ }
7973
+ identifiers.add(lastSegment);
7974
+ }
7975
+ return [...identifiers].sort();
7976
+ }
7977
+ function deriveRlsPolicyScopeInventory(repoPath, repoFiles) {
7978
+ const candidatePolicyFiles = findRlsPolicyFiles(repoPath, repoFiles);
7979
+ const policyFiles = /* @__PURE__ */ new Set();
7980
+ const scopeIdentifiers = /* @__PURE__ */ new Set();
7981
+ let policyCount = 0;
7982
+ for (const file of candidatePolicyFiles) {
7983
+ let content;
7984
+ try {
7985
+ content = readFileSync(join(repoPath, file), "utf8");
7986
+ } catch {
7987
+ continue;
7988
+ }
7989
+ for (const match of content.matchAll(/\bcreate\s+policy\b[\s\S]*?(?:;|$)/gi)) {
7990
+ const statement = match[0];
7991
+ const clauses = [
7992
+ ...extractBalancedSqlClause(statement, "using"),
7993
+ ...extractBalancedSqlClause(statement, "with check")
7994
+ ];
7995
+ if (clauses.length === 0) continue;
7996
+ policyCount += 1;
7997
+ policyFiles.add(file);
7998
+ for (const clause of clauses) {
7999
+ for (const identifier of extractRlsScopeIdentifiers(clause)) {
8000
+ scopeIdentifiers.add(identifier);
8001
+ }
8002
+ }
8003
+ }
8004
+ }
8005
+ const identifiers = [...scopeIdentifiers].sort();
8006
+ const dataLayerFiles = repoFiles.filter(
8007
+ (file) => /(^|\/)(?:migrations?|drizzle|prisma)\/|\.(?:sql|prisma)$/i.test(file)
8008
+ );
8009
+ const storageFiles = identifiers.length === 0 ? [] : dataLayerFiles.filter(
8010
+ (file) => identifiers.some(
8011
+ (identifier) => fileContains(
8012
+ repoPath,
8013
+ file,
8014
+ new RegExp(`\\b${identifier.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\b`, "i")
8015
+ )
8016
+ )
8017
+ );
8018
+ return {
8019
+ policyFiles: [...policyFiles].sort(),
8020
+ policyCount,
8021
+ scopeIdentifiers: identifiers,
8022
+ storageFiles
8023
+ };
8024
+ }
7861
8025
  function findDeployableServicePremiseFiles(repoPath, repoFiles, strictOperationalBoundary = false) {
7862
8026
  const explicitTargets = repoFiles.filter(
7863
8027
  (file) => isAuthoredProductionPath(file) && isExplicitDeployTarget(file) && (!strictOperationalBoundary || isV47OperationalApplicationPath(file))
@@ -9606,6 +9770,9 @@ var WITAN_RUBRIC = [
9606
9770
  ];
9607
9771
 
9608
9772
  // src/witan/scoring.ts
9773
+ function usesV17DetectorClosure2(rubricVersion) {
9774
+ return rubricVersion === WITAN_RUBRIC_VERSION_V17 || rubricVersion === WITAN_RUBRIC_VERSION_V18;
9775
+ }
9609
9776
  var MAX_SIGNAL_ADJUSTMENT = 0.8;
9610
9777
  function createWitanReport(input, inputSignals, rubric = WITAN_RUBRIC) {
9611
9778
  const parsedInput = WitanReportInputSchema.parse(input);
@@ -9689,7 +9856,7 @@ function createWitanReport(input, inputSignals, rubric = WITAN_RUBRIC) {
9689
9856
  const isFreeCoreRubric = rubric.length === WITAN_RUBRIC.length && rubric.every(
9690
9857
  ({ id, category }, index) => id === WITAN_RUBRIC[index]?.id && category === WITAN_RUBRIC[index]?.category
9691
9858
  );
9692
- const noMeasurementAbstention = (parsedInput.rubricVersion === WITAN_RUBRIC_VERSION_V16 || parsedInput.rubricVersion === WITAN_RUBRIC_VERSION_V17) && isFreeCoreRubric && !hasMeasuredCriterion;
9859
+ const noMeasurementAbstention = (parsedInput.rubricVersion === WITAN_RUBRIC_VERSION_V16 || usesV17DetectorClosure2(parsedInput.rubricVersion)) && isFreeCoreRubric && !hasMeasuredCriterion;
9693
9860
  const insufficientSourceReason = parsedInput.insufficientSourceReason ?? (noMeasurementAbstention ? WITAN_NO_MEASUREMENT_REASON : void 0);
9694
9861
  const abstained = insufficientSourceReason != null;
9695
9862
  return WitanReportSchema.parse({
@@ -9757,7 +9924,7 @@ function statusForScore(score) {
9757
9924
  }
9758
9925
  function statusAfterInputAdjustment(nativeStatus, nativeScore, adjustment, rubricVersion) {
9759
9926
  if (adjustment === 0) return nativeStatus;
9760
- if (rubricVersion !== WITAN_RUBRIC_VERSION_V8 && rubricVersion !== WITAN_RUBRIC_VERSION_V92 && 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) {
9927
+ 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) {
9761
9928
  return statusForScore(roundScore(Math.max(0, nativeScore - adjustment)));
9762
9929
  }
9763
9930
  const statusFloor = {
@@ -9801,7 +9968,7 @@ function mergeSignalsByCriterion(signals) {
9801
9968
  return merged;
9802
9969
  }
9803
9970
  function usesMetricScoring(rubricVersion) {
9804
- 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_V92 || 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_TRADING_RUBRIC_VERSION_V0;
9971
+ 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_TRADING_RUBRIC_VERSION_V0;
9805
9972
  }
9806
9973
  function unmeasuredStatus(rubricVersion) {
9807
9974
  return rubricVersion === WITAN_TRADING_RUBRIC_VERSION_V0 ? "unverified" : "insufficient_data";
@@ -9932,7 +10099,7 @@ function scoreMetrics(metrics) {
9932
10099
  function capScoreForFindings(score, findings, rubricVersion, criterionId) {
9933
10100
  if (findings.some((finding) => finding.severity === "critical")) {
9934
10101
  const criticalFindings = findings.filter(({ severity }) => severity === "critical");
9935
- const authenticatedA1Absence = rubricVersion === WITAN_RUBRIC_VERSION_V17 && criterionId === "A1" && criticalFindings.length === 1 && criticalFindings[0]?.summary === WITAN_AUTHENTICATED_A1_ABSENCE_SUMMARY;
10102
+ const authenticatedA1Absence = usesV17DetectorClosure2(rubricVersion) && criterionId === "A1" && criticalFindings.length === 1 && criticalFindings[0]?.summary === WITAN_AUTHENTICATED_A1_ABSENCE_SUMMARY;
9936
10103
  return authenticatedA1Absence ? Math.min(score, 1.4) : 1.4;
9937
10104
  }
9938
10105
  if (findings.some((finding) => finding.severity === "warning")) return Math.min(score, 2.4);
@@ -9941,8 +10108,8 @@ function capScoreForFindings(score, findings, rubricVersion, criterionId) {
9941
10108
  }
9942
10109
  function statusForScoreAndFindings(criterionId, score, findings, metrics, rubricVersion) {
9943
10110
  if (findings.some((finding) => finding.severity === "critical")) return "critical";
9944
- if (rubricVersion === WITAN_RUBRIC_VERSION_V8 || rubricVersion === WITAN_RUBRIC_VERSION_V92 || 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) {
9945
- const calibrated = 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 ? calibratedCriterionStateV11(criterionId, metrics) : rubricVersion === WITAN_RUBRIC_VERSION_V92 || rubricVersion === WITAN_RUBRIC_VERSION_V10 ? calibratedCriterionStateV9(criterionId, metrics) : calibratedCriterionStateV8(criterionId, metrics);
10111
+ 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 || usesV17DetectorClosure2(rubricVersion)) {
10112
+ const calibrated = 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 || usesV17DetectorClosure2(rubricVersion) ? calibratedCriterionStateV11(criterionId, metrics) : rubricVersion === WITAN_RUBRIC_VERSION_V9 || rubricVersion === WITAN_RUBRIC_VERSION_V10 ? calibratedCriterionStateV9(criterionId, metrics) : calibratedCriterionStateV8(criterionId, metrics);
9946
10113
  if (calibrated && calibrated !== "verified") return calibrated;
9947
10114
  if (calibrated === "verified" && !findings.some((finding) => finding.severity === "warning")) {
9948
10115
  return "verified";
@@ -10168,7 +10335,7 @@ function calibratedCriterionStateV11(criterionId, metrics) {
10168
10335
  return void 0;
10169
10336
  }
10170
10337
  function ensureFindingsExplainStatus(criterionId, score, status, findings, evidence, rubricVersion) {
10171
- if (rubricVersion !== WITAN_RUBRIC_VERSION_V8 && rubricVersion !== WITAN_RUBRIC_VERSION_V92 && 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 && findings.length > 0) {
10338
+ 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 && findings.length > 0) {
10172
10339
  return [...findings];
10173
10340
  }
10174
10341
  if (status !== "critical" && status !== "warning") return [...findings];
@@ -10213,7 +10380,18 @@ function scoreRepoWithPublicCejel(options) {
10213
10380
  ...options.rubricVersion ? { rubricVersion: options.rubricVersion } : {}
10214
10381
  });
10215
10382
  const inputSignals = resolvePublicIngestSignals(options);
10216
- return createWitanReport(input, inputSignals.length > 0 ? inputSignals : void 0);
10383
+ const report = createWitanReport(input, inputSignals.length > 0 ? inputSignals : void 0);
10384
+ if (report.verdict !== "insufficient_source" || !isWitanNoMeasurementAbstention(report)) {
10385
+ return report;
10386
+ }
10387
+ const contextualReason = explainNoMeasurementSourceCoverage(
10388
+ options.repoPath,
10389
+ report.rubricVersion
10390
+ );
10391
+ return contextualReason ? {
10392
+ ...report,
10393
+ insufficientSourceReason: contextualReason
10394
+ } : report;
10217
10395
  }
10218
10396
  function resolvePublicIngestSignals(options) {
10219
10397
  const seen = /* @__PURE__ */ new Set();
package/dist/index.js CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  runCejelScan,
10
10
  serializeWitanReport,
11
11
  verifyWitanAttestationBinding
12
- } from "./chunk-EFOUXVJE.js";
12
+ } from "./chunk-BR2DO4QJ.js";
13
13
 
14
14
  // src/index.ts
15
15
  import { createHash } from "crypto";
package/dist/mcp/index.js CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  renderWitanBadgeSvg,
11
11
  renderWitanHtmlReport,
12
12
  runCejelScan
13
- } from "../chunk-EFOUXVJE.js";
13
+ } from "../chunk-BR2DO4QJ.js";
14
14
 
15
15
  // node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/compile/codegen/code.js
16
16
  var require_code = __commonJS({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cejel/cejel",
3
- "version": "0.1.10",
3
+ "version": "0.2.1",
4
4
  "mcpName": "io.github.BargLabs/cejel",
5
5
  "private": false,
6
6
  "publishConfig": {
@@ -44,6 +44,16 @@
44
44
  "engines": {
45
45
  "node": ">=18"
46
46
  },
47
+ "scripts": {
48
+ "build": "tsup",
49
+ "build:sea-js": "tsup --config tsup.public-sea.config.ts",
50
+ "validate:distribution": "node scripts/validate-distribution-metadata.mjs",
51
+ "prepublishOnly": "pnpm run build",
52
+ "prepack": "pnpm run build",
53
+ "dev": "tsx src/index.ts",
54
+ "typecheck": "tsc --noEmit -p tsconfig.json",
55
+ "test": "vitest run"
56
+ },
47
57
  "devDependencies": {
48
58
  "@modelcontextprotocol/sdk": "^1.0.0",
49
59
  "@types/node": "^25.9.1",
@@ -53,13 +63,5 @@
53
63
  "typescript": "^5.5.0",
54
64
  "vitest": "^2.0.0",
55
65
  "zod": "^3.23.0"
56
- },
57
- "scripts": {
58
- "build": "tsup",
59
- "build:sea-js": "tsup --config tsup.public-sea.config.ts",
60
- "validate:distribution": "node scripts/validate-distribution-metadata.mjs",
61
- "dev": "tsx src/index.ts",
62
- "typecheck": "tsc --noEmit -p tsconfig.json",
63
- "test": "vitest run"
64
66
  }
65
- }
67
+ }