mjolnir-qa 0.5.23 → 0.5.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -9,6 +9,12 @@ Rule behavior changes (new rules, FP-rate changes against the corpus,
9
9
  severity changes) are first-class entries here — rule IDs are immutable
10
10
  once shipped, so this file is the record of what changed between versions.
11
11
 
12
+ ## [0.5.24] — 2026-09-08
13
+
14
+ ### Changes since 0.5.23
15
+
16
+ - L4 ruling: tier-enforcement INCONCLUSIVE without live verdicts (MEASURED_FP = historical artifact only) (#58)
17
+
12
18
  ## [0.5.23] — 2026-09-08
13
19
 
14
20
  ### Changes since 0.5.22
package/dist/cli.d.mts CHANGED
@@ -728,7 +728,7 @@ declare const runScan: typeof runScan$1, buildUniversalRules: typeof buildUniver
728
728
  * `scripts/sync-sarif-version.cjs` on release and guarded by
729
729
  * `tests/version-consistency.spec.ts` locally.
730
730
  */
731
- declare const CLI_VERSION = "0.5.23";
731
+ declare const CLI_VERSION = "0.5.24";
732
732
  /** A usage-error detail: the offending token, when one exists. */
733
733
  interface UsageErrorDetail {
734
734
  /** The unknown flag or rejected value (e.g. `--nope`, `loud`). */
package/dist/cli.mjs CHANGED
@@ -13290,7 +13290,7 @@ function renderSarif(result, repoRootUri) {
13290
13290
  tool: { driver: {
13291
13291
  name: "Mjölnir",
13292
13292
  informationUri: "https://github.com/Sergey-Bar/Mjolnir",
13293
- version: "0.5.23",
13293
+ version: "0.5.24",
13294
13294
  rules: [...rules.values()].map((r) => {
13295
13295
  const meta = RULES.find((x) => x.id === r.id);
13296
13296
  return {
@@ -18025,14 +18025,16 @@ function measurementBlock(rules = RULES) {
18025
18025
  */
18026
18026
  function checkTierEnforcement(verdictsDir, rules = RULES) {
18027
18027
  const details = [];
18028
+ if (!existsSync(verdictsDir)) return check("tier-enforcement", "inconclusive", ["INCONCLUSIVE: live verdicts unavailable (tests/corpus/verdicts missing — installed package) — tier claims cannot be proven without live evidence; MEASURED_FP is a historical artifact and does not substitute (owner ruling 2026-09-08, L4)"]);
18028
18029
  const classifiedPerRule = /* @__PURE__ */ new Map();
18029
18030
  const byId = new Map(rules.map((r) => [r.id, r]));
18030
18031
  for (const [id, m] of Object.entries(MEASURED_FP)) {
18031
18032
  const rule = byId.get(id);
18032
18033
  if (rule && m.detectorRevision === declaredDetectorRevision(rule)) classifiedPerRule.set(id, m.n);
18033
18034
  }
18035
+ let live;
18034
18036
  try {
18035
- const live = /* @__PURE__ */ new Map();
18037
+ live = /* @__PURE__ */ new Map();
18036
18038
  const files = readdirSync(verdictsDir).filter((f) => f.endsWith(".jsonl"));
18037
18039
  for (const f of files) {
18038
18040
  const lines = readFileSync(join(verdictsDir, f), "utf8").split("\n").filter((l) => l.trim().length > 0);
@@ -18041,8 +18043,10 @@ function checkTierEnforcement(verdictsDir, rules = RULES) {
18041
18043
  if (entry.verdict === "TP" || entry.verdict === "FP") live.set(entry.ruleId, (live.get(entry.ruleId) ?? 0) + 1);
18042
18044
  } catch {}
18043
18045
  }
18044
- if (live.size > 0) for (const [id, n] of live) classifiedPerRule.set(id, n);
18045
- } catch {}
18046
+ } catch (e) {
18047
+ return check("tier-enforcement", "inconclusive", [`INCONCLUSIVE: live verdicts unreadable — ${errorText(e)} (owner ruling 2026-09-08, L4)`]);
18048
+ }
18049
+ if (live.size > 0) for (const [id, n] of live) classifiedPerRule.set(id, n);
18046
18050
  const coreRules = rules.filter((r) => effectiveTier(r) === "core");
18047
18051
  for (const r of coreRules) {
18048
18052
  const n = classifiedPerRule.get(r.id) ?? 0;
@@ -18619,7 +18623,7 @@ const { runScan, buildUniversalRules, fallbackWorkspace, pathMatchesGlob, isVali
18619
18623
  * `scripts/sync-sarif-version.cjs` on release and guarded by
18620
18624
  * `tests/version-consistency.spec.ts` locally.
18621
18625
  */
18622
- const CLI_VERSION = "0.5.23";
18626
+ const CLI_VERSION = "0.5.24";
18623
18627
  function parseArgs(argv, onError) {
18624
18628
  const args = {
18625
18629
  target: ".",
@@ -13289,7 +13289,7 @@ function renderSarif(result, repoRootUri) {
13289
13289
  tool: { driver: {
13290
13290
  name: "Mjölnir",
13291
13291
  informationUri: "https://github.com/Sergey-Bar/Mjolnir",
13292
- version: "0.5.23",
13292
+ version: "0.5.24",
13293
13293
  rules: [...rules.values()].map((r) => {
13294
13294
  const meta = RULES.find((x) => x.id === r.id);
13295
13295
  return {
@@ -17507,14 +17507,16 @@ function measurementBlock(rules = RULES) {
17507
17507
  */
17508
17508
  function checkTierEnforcement(verdictsDir, rules = RULES) {
17509
17509
  const details = [];
17510
+ if (!existsSync(verdictsDir)) return check("tier-enforcement", "inconclusive", ["INCONCLUSIVE: live verdicts unavailable (tests/corpus/verdicts missing — installed package) — tier claims cannot be proven without live evidence; MEASURED_FP is a historical artifact and does not substitute (owner ruling 2026-09-08, L4)"]);
17510
17511
  const classifiedPerRule = /* @__PURE__ */ new Map();
17511
17512
  const byId = new Map(rules.map((r) => [r.id, r]));
17512
17513
  for (const [id, m] of Object.entries(MEASURED_FP)) {
17513
17514
  const rule = byId.get(id);
17514
17515
  if (rule && m.detectorRevision === declaredDetectorRevision(rule)) classifiedPerRule.set(id, m.n);
17515
17516
  }
17517
+ let live;
17516
17518
  try {
17517
- const live = /* @__PURE__ */ new Map();
17519
+ live = /* @__PURE__ */ new Map();
17518
17520
  const files = readdirSync(verdictsDir).filter((f) => f.endsWith(".jsonl"));
17519
17521
  for (const f of files) {
17520
17522
  const lines = readFileSync(join(verdictsDir, f), "utf8").split("\n").filter((l) => l.trim().length > 0);
@@ -17523,8 +17525,10 @@ function checkTierEnforcement(verdictsDir, rules = RULES) {
17523
17525
  if (entry.verdict === "TP" || entry.verdict === "FP") live.set(entry.ruleId, (live.get(entry.ruleId) ?? 0) + 1);
17524
17526
  } catch {}
17525
17527
  }
17526
- if (live.size > 0) for (const [id, n] of live) classifiedPerRule.set(id, n);
17527
- } catch {}
17528
+ } catch (e) {
17529
+ return check("tier-enforcement", "inconclusive", [`INCONCLUSIVE: live verdicts unreadable — ${errorText(e)} (owner ruling 2026-09-08, L4)`]);
17530
+ }
17531
+ if (live.size > 0) for (const [id, n] of live) classifiedPerRule.set(id, n);
17528
17532
  const coreRules = rules.filter((r) => effectiveTier(r) === "core");
17529
17533
  for (const r of coreRules) {
17530
17534
  const n = classifiedPerRule.get(r.id) ?? 0;
@@ -18255,7 +18259,7 @@ const { runScan, buildUniversalRules, fallbackWorkspace, pathMatchesGlob, isVali
18255
18259
  * `scripts/sync-sarif-version.cjs` on release and guarded by
18256
18260
  * `tests/version-consistency.spec.ts` locally.
18257
18261
  */
18258
- const CLI_VERSION = "0.5.23";
18262
+ const CLI_VERSION = "0.5.24";
18259
18263
  function parseArgs(argv, onError) {
18260
18264
  const args = {
18261
18265
  target: ".",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mjolnir-qa",
3
- "version": "0.5.23",
3
+ "version": "0.5.24",
4
4
  "description": "Mjölnir — the Verification Trust Engine for QA. Audits test suites and CI pipelines, reports a worthiness score and prioritized findings.",
5
5
  "type": "module",
6
6
  "engines": {