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 +6 -0
- package/dist/cli.d.mts +1 -1
- package/dist/cli.mjs +9 -5
- package/dist/mcp/stdio.mjs +9 -5
- package/package.json +1 -1
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.
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
18045
|
-
|
|
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.
|
|
18626
|
+
const CLI_VERSION = "0.5.24";
|
|
18623
18627
|
function parseArgs(argv, onError) {
|
|
18624
18628
|
const args = {
|
|
18625
18629
|
target: ".",
|
package/dist/mcp/stdio.mjs
CHANGED
|
@@ -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.
|
|
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
|
-
|
|
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
|
-
|
|
17527
|
-
|
|
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.
|
|
18262
|
+
const CLI_VERSION = "0.5.24";
|
|
18259
18263
|
function parseArgs(argv, onError) {
|
|
18260
18264
|
const args = {
|
|
18261
18265
|
target: ".",
|
package/package.json
CHANGED