mjolnir-qa 3.0.0 → 5.0.0
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 +628 -6
- package/README.ar.md +58 -29
- package/README.bn.md +58 -29
- package/README.br.md +58 -29
- package/README.bs.md +58 -29
- package/README.da.md +59 -30
- package/README.de.md +59 -30
- package/README.es.md +58 -29
- package/README.fr.md +59 -30
- package/README.gr.md +58 -29
- package/README.he.md +58 -29
- package/README.it.md +58 -29
- package/README.ja.md +58 -29
- package/README.ko.md +58 -29
- package/README.md +95 -56
- package/README.no.md +58 -29
- package/README.pl.md +58 -29
- package/README.ru.md +58 -29
- package/README.th.md +58 -29
- package/README.tr.md +58 -29
- package/README.uk.md +58 -29
- package/README.vi.md +58 -29
- package/README.zh.md +58 -29
- package/README.zht.md +58 -29
- package/dist/cli.d.mts +398 -17
- package/dist/cli.mjs +2893 -1005
- package/dist/mcp/stdio.mjs +1576 -715
- package/dist/scan-pipeline-DNYbnWjE.mjs +2 -0
- package/dist/{scan-pipeline-CAH9_Qgh.mjs → scan-pipeline-DT8DWAMl.mjs} +1777 -978
- package/package.json +70 -9
- package/dist/scan-pipeline-CRe7-MQn.mjs +0 -2
package/dist/cli.d.mts
CHANGED
|
@@ -1,3 +1,77 @@
|
|
|
1
|
+
//#region src/v6/test-doubles.d.ts
|
|
2
|
+
/** How serious the pattern is. Closed enum, so a renderer cannot invent a
|
|
3
|
+
* fourth severity at a call site. */
|
|
4
|
+
declare const DOUBLE_RISKS: readonly ["NO_ASSERTION", "DOUBLE_ONLY", "DOUBLE_MIXED", "DOUBLE_SUBJECT"];
|
|
5
|
+
type DoubleRisk = (typeof DOUBLE_RISKS)[number];
|
|
6
|
+
interface DoubleFinding {
|
|
7
|
+
risk: DoubleRisk;
|
|
8
|
+
/** How many assertions there are in total. */
|
|
9
|
+
assertions: number;
|
|
10
|
+
/** How many are about a double. */
|
|
11
|
+
doubleAssertions: number;
|
|
12
|
+
/** How many carry real evidence about the code under test. */
|
|
13
|
+
substantiatingAssertions: number;
|
|
14
|
+
/** 0..1 — the share of assertions that prove nothing. */
|
|
15
|
+
hollowRatio: number;
|
|
16
|
+
/** The one-line statement a surface can render verbatim. */
|
|
17
|
+
statement: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* A roll-up across a suite. A suite is hollow when *no* test in it
|
|
21
|
+
* substantiates anything — which is a different and stronger statement
|
|
22
|
+
* than "some tests are hollow", and the one a user needs at the top of a
|
|
23
|
+
* report.
|
|
24
|
+
*/
|
|
25
|
+
declare function assessSuite(findings: readonly DoubleFinding[]): {
|
|
26
|
+
tests: number;
|
|
27
|
+
hollow: number;
|
|
28
|
+
substantiating: number;
|
|
29
|
+
hollowRatio: number;
|
|
30
|
+
verdict: "SUBSTANTIATED" | "PARTIALLY_HOLLOW" | "HOLLOW";
|
|
31
|
+
};
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region src/v6/tool-coverage.d.ts
|
|
34
|
+
/** What the engine can do with a detected tool. Closed enum, so a
|
|
35
|
+
* renderer cannot invent a fifth state. */
|
|
36
|
+
declare const TOOL_COVERAGE_STATES: readonly ["UNDERSTOOD", "DECLARED", "OUT_OF_SCOPE", "IGNORED"];
|
|
37
|
+
type ToolCoverageState = (typeof TOOL_COVERAGE_STATES)[number];
|
|
38
|
+
interface ToolCoverageEntry {
|
|
39
|
+
name: string;
|
|
40
|
+
state: ToolCoverageState;
|
|
41
|
+
/** The census category, when one applies. */
|
|
42
|
+
category: string | null;
|
|
43
|
+
/** The census entry id, when the engine has one. */
|
|
44
|
+
censusId: string | null;
|
|
45
|
+
/** What the cost of not handling it is, in one sentence. */
|
|
46
|
+
consequence: string;
|
|
47
|
+
}
|
|
48
|
+
interface BlindSpot {
|
|
49
|
+
id: string;
|
|
50
|
+
/** What the engine cannot see. */
|
|
51
|
+
blindTo: string;
|
|
52
|
+
/** Why it matters, in one sentence. */
|
|
53
|
+
consequence: string;
|
|
54
|
+
}
|
|
55
|
+
interface ToolCoverage {
|
|
56
|
+
/** Every QA tool the probe saw, with what the engine does about it. */
|
|
57
|
+
tools: readonly ToolCoverageEntry[];
|
|
58
|
+
counts: Readonly<Record<ToolCoverageState, number>>;
|
|
59
|
+
/** Tools the engine sees and cannot act on. */
|
|
60
|
+
unhandled: readonly ToolCoverageEntry[];
|
|
61
|
+
/**
|
|
62
|
+
* What the engine cannot see **through**, whether or not the tool is
|
|
63
|
+
* known. This is the part a user cannot infer, and the part that makes
|
|
64
|
+
* a green run mean something.
|
|
65
|
+
*/
|
|
66
|
+
blindSpots: readonly BlindSpot[];
|
|
67
|
+
/** The double-analysis roll-up, when the caller supplied test data. */
|
|
68
|
+
suite: ReturnType<typeof assessSuite> | null;
|
|
69
|
+
/** One line a surface may render verbatim. */
|
|
70
|
+
statement: string;
|
|
71
|
+
/** Never a claim of completeness. */
|
|
72
|
+
complete: false;
|
|
73
|
+
}
|
|
74
|
+
//#endregion
|
|
1
75
|
//#region src/types.d.ts
|
|
2
76
|
/**
|
|
3
77
|
* Mjolnir — canonical types (JSON contract v1, schemaVersion 1).
|
|
@@ -235,6 +309,68 @@ interface DimensionScore {
|
|
|
235
309
|
infos: number;
|
|
236
310
|
}
|
|
237
311
|
type AnalysisStatus = "complete" | "partial";
|
|
312
|
+
/**
|
|
313
|
+
* The normalized per-test runtime evidence record as it appears in a report
|
|
314
|
+
* (plan V5-011). Structurally the `EvidenceRecord` from
|
|
315
|
+
* `src/engine/evidence-core.ts`, restated here so the report schema does not
|
|
316
|
+
* depend on an engine module's internals — the wire shape is a contract.
|
|
317
|
+
*/
|
|
318
|
+
interface EvidenceRecordShape {
|
|
319
|
+
source: string;
|
|
320
|
+
artifact: string;
|
|
321
|
+
file: string;
|
|
322
|
+
title: string;
|
|
323
|
+
line?: number;
|
|
324
|
+
status: {
|
|
325
|
+
final: string;
|
|
326
|
+
failed: boolean;
|
|
327
|
+
retried: boolean;
|
|
328
|
+
passedOnRetry: boolean;
|
|
329
|
+
skipped: boolean;
|
|
330
|
+
timedOut: boolean;
|
|
331
|
+
};
|
|
332
|
+
attempts: number;
|
|
333
|
+
durationMs: number;
|
|
334
|
+
errors: string[];
|
|
335
|
+
attachments: string[];
|
|
336
|
+
provenance: {
|
|
337
|
+
core: string;
|
|
338
|
+
ingest: string;
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Candidate binding (plan V5-010).
|
|
343
|
+
*
|
|
344
|
+
* The immutable identity of the release candidate a run was produced against.
|
|
345
|
+
* It is what makes a claim replayable: "this verdict belongs to candidate
|
|
346
|
+
* X, built from commit Y with lockfile Z" can be re-checked; "this verdict
|
|
347
|
+
* belongs to whatever was on the machine" cannot.
|
|
348
|
+
*
|
|
349
|
+
* Every field is required. A partial binding is worse than none, because a
|
|
350
|
+
* consumer cannot tell which link is missing — so an unbound run omits the
|
|
351
|
+
* whole object rather than filling in what it has.
|
|
352
|
+
*/
|
|
353
|
+
interface CandidateBinding {
|
|
354
|
+
/** The candidate manifest's own id. */
|
|
355
|
+
manifestId: string;
|
|
356
|
+
/** WORKING_CANDIDATE | RELEASE_CANDIDATE. */
|
|
357
|
+
state: "WORKING_CANDIDATE" | "RELEASE_CANDIDATE";
|
|
358
|
+
/**
|
|
359
|
+
* The immutable commit this candidate is bound to, or null for a working
|
|
360
|
+
* candidate — which by definition has no commit yet.
|
|
361
|
+
*/
|
|
362
|
+
candidateSha: string | null;
|
|
363
|
+
/** The commit the candidate was branched from. */
|
|
364
|
+
baseSha: string;
|
|
365
|
+
/** sha256 of package.json as published for the candidate. */
|
|
366
|
+
packageSha256: string;
|
|
367
|
+
/** sha256 of the lockfile as published for the candidate. */
|
|
368
|
+
lockfileSha256: string;
|
|
369
|
+
/** Who owns the candidate. "UNASSIGNED" is a real, reportable value. */
|
|
370
|
+
owner: string;
|
|
371
|
+
/** NOT_AUTHORIZED | AUTHORIZED. Never inferred from evidence. */
|
|
372
|
+
releaseAuthorizationState: "NOT_AUTHORIZED" | "AUTHORIZED";
|
|
373
|
+
}
|
|
238
374
|
interface ScanResult {
|
|
239
375
|
schemaVersion: typeof SCHEMA_VERSION;
|
|
240
376
|
/** False when budget expired or files were skipped (§18.3). */
|
|
@@ -321,12 +457,42 @@ interface ScanResult {
|
|
|
321
457
|
durationMs: number;
|
|
322
458
|
/**
|
|
323
459
|
* Named reasons the scan stopped early (audit H-8): "deadline",
|
|
324
|
-
* "file-cap:<adapter>", "rule-loop-deadline".
|
|
325
|
-
* truncation actually happened — absence means the
|
|
460
|
+
* "file-cap:<adapter>", "rule-loop-deadline", "ast-budget-fallback".
|
|
461
|
+
* Present only when truncation actually happened — absence means the
|
|
462
|
+
* scan is whole.
|
|
463
|
+
*
|
|
464
|
+
* Open `string[]`, NOT a closed union: a producer may add a member
|
|
465
|
+
* without a schema bump. The cost of that choice is that a consumer
|
|
466
|
+
* asserting the EXACT set breaks on every new reason, so assertions
|
|
467
|
+
* here are containment assertions, never `toEqual([...])`.
|
|
468
|
+
*
|
|
469
|
+
* "ast-budget-fallback" specifically means the scan ran out of time
|
|
470
|
+
* before a file could be analyzed through its adapter's AST stage, and
|
|
471
|
+
* that file was analyzed by regex instead. It is a capability loss, not
|
|
472
|
+
* a speed trade, and the count of affected files is in `reasons` as
|
|
473
|
+
* "ast-budget-fallback-files:<n>".
|
|
326
474
|
*/
|
|
327
475
|
truncationReasons?: string[];
|
|
328
476
|
/** Canonical completion reasons, including scope and parser degradation. */
|
|
329
477
|
reasons?: string[];
|
|
478
|
+
/**
|
|
479
|
+
* Per-reason counts of capability lost inside a `catch` that returned a
|
|
480
|
+
* clean default — the degradation ledger (`src/engine/degradation-ledger.ts`).
|
|
481
|
+
*
|
|
482
|
+
* Distinct from `truncationReasons`, which means the scan STOPPED, and
|
|
483
|
+
* from `reasons`, which is a flat string set. This one is structured and
|
|
484
|
+
* reason-coded so "the AST mask was unavailable for 3 files" and "3 files
|
|
485
|
+
* were skipped" cannot be confused. Each entry is ALSO surfaced in
|
|
486
|
+
* `reasons` as `degraded:<reason>:<count>`.
|
|
487
|
+
*
|
|
488
|
+
* Present only when at least one degradation happened; absence means the
|
|
489
|
+
* scan lost no capability to a swallowed error, OR the producer predates
|
|
490
|
+
* the ledger. A non-empty value always forces `partial: true`.
|
|
491
|
+
*/
|
|
492
|
+
degradations?: Array<{
|
|
493
|
+
reason: string;
|
|
494
|
+
count: number;
|
|
495
|
+
}>;
|
|
330
496
|
/**
|
|
331
497
|
* Rule executions that threw and were swallowed by crash isolation
|
|
332
498
|
* (audit R-9). 0 means no rule silently failed; absence means the
|
|
@@ -367,6 +533,18 @@ interface ScanResult {
|
|
|
367
533
|
/** The named scope reasons, present only when PARTIAL. */
|
|
368
534
|
reasons?: string[];
|
|
369
535
|
};
|
|
536
|
+
/**
|
|
537
|
+
* Tool coverage (v6): which QA tooling this scan actually saw, what the
|
|
538
|
+
* engine does about it, and what it is blind to.
|
|
539
|
+
*
|
|
540
|
+
* Present when the scan ran the ecosystem probe. Additive within
|
|
541
|
+
* schemaVersion 1; absent when the producer predates this field.
|
|
542
|
+
*
|
|
543
|
+
* complete is always false. A scan that could not see through a test
|
|
544
|
+
* double must never render as a scan with no blind spots, and that is
|
|
545
|
+
* the one claim a verification tool cannot make.
|
|
546
|
+
*/
|
|
547
|
+
toolCoverage?: ToolCoverage;
|
|
370
548
|
/**
|
|
371
549
|
* Run Identity (R4c): the deterministic anchor binding verdict ←
|
|
372
550
|
* evidence ← execution ← scope ← source ← rule(rev). Present when the
|
|
@@ -382,6 +560,29 @@ interface ScanResult {
|
|
|
382
560
|
scoringModelVersion?: string;
|
|
383
561
|
frameworkSupportMatrixVersion?: string;
|
|
384
562
|
commit?: string;
|
|
563
|
+
/** The worktree tree hash the run was bound to, when known. */
|
|
564
|
+
tree?: string;
|
|
565
|
+
/** The lockfile digest the run was bound to, when known. */
|
|
566
|
+
lockfile?: string;
|
|
567
|
+
/**
|
|
568
|
+
* Which identity links this run actually bound (plan V5-010). Derived, not
|
|
569
|
+
* asserted by each consumer: a claim is replayable only when every link it
|
|
570
|
+
* depends on is present.
|
|
571
|
+
*
|
|
572
|
+
* OPTIONAL on purpose. The machine contract is v1 additive-only, so a
|
|
573
|
+
* report written before this field existed has none, and a reader that
|
|
574
|
+
* required it would reject exactly the older artifacts it must tolerate.
|
|
575
|
+
* Absence means "produced by a build that did not record bindings" — never
|
|
576
|
+
* "bound to everything".
|
|
577
|
+
*/
|
|
578
|
+
boundLinks?: Array<"input" | "rules" | "config" | "engine" | "commit" | "tree" | "lockfile" | "candidate">;
|
|
579
|
+
/**
|
|
580
|
+
* The release candidate this run is bound to (plan V5-010). Absent for an
|
|
581
|
+
* ordinary scan of a working tree — a run is not a release candidate, and
|
|
582
|
+
* saying otherwise would let a local scan stand in for authorized
|
|
583
|
+
* evidence.
|
|
584
|
+
*/
|
|
585
|
+
candidate?: CandidateBinding;
|
|
385
586
|
};
|
|
386
587
|
/**
|
|
387
588
|
* Evidence Graph (R4c): the chain-law links (VERDICT ← EVIDENCE ←
|
|
@@ -401,6 +602,34 @@ interface ScanResult {
|
|
|
401
602
|
configFingerprint: string;
|
|
402
603
|
engineVersion: string;
|
|
403
604
|
};
|
|
605
|
+
/** The release candidate the verdict belongs to, when bound (V5-010). */
|
|
606
|
+
candidate?: {
|
|
607
|
+
manifestId: string;
|
|
608
|
+
candidateSha: string | null;
|
|
609
|
+
};
|
|
610
|
+
};
|
|
611
|
+
/**
|
|
612
|
+
* The normalized evidence core (plan V5-011).
|
|
613
|
+
*
|
|
614
|
+
* Present whenever the run ingested a runtime report. `records` is the
|
|
615
|
+
* canonical, deterministically-ordered set that every downstream consumer
|
|
616
|
+
* reads — before this, the core was computed and discarded inside the
|
|
617
|
+
* pipeline, so a re-derivation had to re-parse the report and could disagree
|
|
618
|
+
* with the verdict it was supposed to explain.
|
|
619
|
+
*
|
|
620
|
+
* Empty `records` with a null `artifact` means no runtime evidence was
|
|
621
|
+
* found, which is different from a run that found an empty report.
|
|
622
|
+
*/
|
|
623
|
+
evidence?: {
|
|
624
|
+
records: Array<EvidenceRecordShape>;
|
|
625
|
+
counts: {
|
|
626
|
+
total: number;
|
|
627
|
+
failed: number;
|
|
628
|
+
flaky: number;
|
|
629
|
+
skipped: number;
|
|
630
|
+
timedOut: number;
|
|
631
|
+
};
|
|
632
|
+
artifact: string | null;
|
|
404
633
|
};
|
|
405
634
|
/**
|
|
406
635
|
* Local incremental cache report (Beta-to-Stable plan, M5.2). Present
|
|
@@ -639,6 +868,56 @@ declare class DependencyGraph {
|
|
|
639
868
|
getDependents(path: string): string[];
|
|
640
869
|
get allPaths(): string[];
|
|
641
870
|
get size(): number;
|
|
871
|
+
/** Whether the graph knows this exact key. Reachability must not
|
|
872
|
+
* treat "not in the graph" as "nothing to traverse" without saying so. */
|
|
873
|
+
has(path: string): boolean;
|
|
874
|
+
}
|
|
875
|
+
//#endregion
|
|
876
|
+
//#region src/engine/degradation-ledger.d.ts
|
|
877
|
+
/**
|
|
878
|
+
* One ledger for every silent capability loss.
|
|
879
|
+
*
|
|
880
|
+
* The defect class this exists to kill is not a deprecation warning. It is a
|
|
881
|
+
* `catch` in a DETECTION path that swallows an error and returns a clean
|
|
882
|
+
* default, so the scan still reports `analysisComplete` while quietly running
|
|
883
|
+
* with less capability than the reader was promised. Fifteen such sites were
|
|
884
|
+
* verified in this tree; the AST-layer ones are the worst, because the layer
|
|
885
|
+
* they degrade is the one that keeps prose comments and sample strings from
|
|
886
|
+
* becoming false-positive findings.
|
|
887
|
+
*
|
|
888
|
+
* Two shapes, one rule. The precedent already in the tree is
|
|
889
|
+
* `parserRetryDegradationCount` (`src/engine/tree-sitter-ast.ts`): a counted,
|
|
890
|
+
* readable number rather than a swallowed exception. This generalizes it —
|
|
891
|
+
* every site records a REASON from the closed set below, and the scan result
|
|
892
|
+
* carries the per-reason counts, so "the parser failed" becomes
|
|
893
|
+
* "the AST mask was unavailable for 3 files".
|
|
894
|
+
*
|
|
895
|
+
* The ledger is APPEND-ONLY and process-scoped, which has one consequence
|
|
896
|
+
* worth stating because it is the security-relevant direction: `beginWindow`
|
|
897
|
+
* returns a MARKER, not an ownership claim. Two concurrent `runScan` calls in
|
|
898
|
+
* one process (there is a test that does exactly this,
|
|
899
|
+
* `tests/stress/concurrent-same-process.spec.ts`) each read the records
|
|
900
|
+
* appended after their own marker, so a degradation one scan records may be
|
|
901
|
+
* counted by the other. That can only ever OVER-count — a scan reporting a
|
|
902
|
+
* degradation that happened to a sibling is more cautious than the truth, and
|
|
903
|
+
* never less — so the failure direction is the honest one. The alternative,
|
|
904
|
+
* a sink threaded through every rule context, is a diff across every call site
|
|
905
|
+
* in the tree to fix a problem that cannot make a scan look better than it is.
|
|
906
|
+
*/
|
|
907
|
+
/**
|
|
908
|
+
* Every reason a detection path may lose capability.
|
|
909
|
+
*
|
|
910
|
+
* Closed on purpose: a `catch` site that wants a new reason has to add it
|
|
911
|
+
* here, which is the moment a reviewer sees the claim. `tests/contract/
|
|
912
|
+
* no-uncounted-degradation.spec.ts` reads this list and fails on any `catch`
|
|
913
|
+
* in a detection path that neither rethrows, records one of these, nor
|
|
914
|
+
* appears in its allowlist with a stated reason.
|
|
915
|
+
*/
|
|
916
|
+
declare const DEGRADATION_REASONS: readonly ["ast-parse-failed", "ast-mask-unavailable", "ast-range-scan-failed", "ci-workflow-listing-unreadable", "workspace-manifest-unreadable", "java-build-listing-unreadable", "rules-tree-listing-unreadable", "trend-record-unparseable", "explain-fixture-unreadable", "explain-workflow-parse-failed", "explain-rule-crash", "rule-doc-rule-crash", "rule-doc-fixture-unreadable", "rule-doc-workflow-parse-failed"];
|
|
917
|
+
type DegradationReason = (typeof DEGRADATION_REASONS)[number];
|
|
918
|
+
interface DegradationCount {
|
|
919
|
+
readonly reason: DegradationReason;
|
|
920
|
+
readonly count: number;
|
|
642
921
|
}
|
|
643
922
|
//#endregion
|
|
644
923
|
//#region src/discovery/workspace.d.ts
|
|
@@ -657,9 +936,18 @@ interface Workspace {
|
|
|
657
936
|
}
|
|
658
937
|
//#endregion
|
|
659
938
|
//#region src/discovery/frameworks.d.ts
|
|
660
|
-
|
|
939
|
+
/**
|
|
940
|
+
* The catalogued frameworks whose detection is implemented today.
|
|
941
|
+
*
|
|
942
|
+
* Every entry must exist in the inventory — enforced by the parity spec, not
|
|
943
|
+
* by comment.
|
|
944
|
+
*/
|
|
945
|
+
declare const DETECTABLE_TEST_FRAMEWORKS: readonly ["jest", "vitest", "playwright"];
|
|
946
|
+
/** The detection output type, in the inventory's vocabulary. */
|
|
947
|
+
type DetectedFramework = (typeof DETECTABLE_TEST_FRAMEWORKS)[number];
|
|
661
948
|
interface FrameworkInfo$1 {
|
|
662
|
-
frameworks
|
|
949
|
+
/** Detected frameworks, as inventory ids. */
|
|
950
|
+
frameworks: DetectedFramework[];
|
|
663
951
|
/** True when no config evidence was found at all. */
|
|
664
952
|
unknown: boolean;
|
|
665
953
|
}
|
|
@@ -991,8 +1279,19 @@ interface LanguageAdapter {
|
|
|
991
1279
|
* Contract: resolve to a ParsedAst on success, `undefined` when this
|
|
992
1280
|
* adapter has no AST layer (or parsing failed — rules fall back to the
|
|
993
1281
|
* regex path either way). Never throws.
|
|
1282
|
+
*
|
|
1283
|
+
* May return the result directly as well as a promise: the ts-morph path
|
|
1284
|
+
* (plan V5-021) is synchronous, and forcing it to allocate a promise per
|
|
1285
|
+
* file would be a cost the shared seam has no business imposing. The
|
|
1286
|
+
* pipeline awaits either form.
|
|
1287
|
+
*
|
|
1288
|
+
* Declared as a PROPERTY, not a method signature. A method signature
|
|
1289
|
+
* promises a `this` binding that no adapter uses, and it makes every
|
|
1290
|
+
* consumer that reads `adapter.parseAst` trip the unbound-method rule —
|
|
1291
|
+
* which is a lint error that gets suppressed rather than a design that
|
|
1292
|
+
* gets fixed, so the shape has to say what it means.
|
|
994
1293
|
*/
|
|
995
|
-
parseAst
|
|
1294
|
+
parseAst?: (file: ParsedFile) => ParsedAst | undefined | Promise<ParsedAst | undefined>;
|
|
996
1295
|
/**
|
|
997
1296
|
* Run all rules this adapter hosts against one file. `onCrash` is
|
|
998
1297
|
* invoked when a rule throws (audit R-9) — the crash is still
|
|
@@ -1045,6 +1344,55 @@ interface UniversalRule {
|
|
|
1045
1344
|
run(file: ParsedFile): Array<Omit<Finding, "ruleId" | "category">>;
|
|
1046
1345
|
}
|
|
1047
1346
|
//#endregion
|
|
1347
|
+
//#region src/engine/evidence-core.d.ts
|
|
1348
|
+
/**
|
|
1349
|
+
* The core's own version — stamped into every record's provenance so a
|
|
1350
|
+
* consumer can tell which normalization contract produced a record.
|
|
1351
|
+
* Bump ONLY on a semantic change to the normalization itself.
|
|
1352
|
+
*/
|
|
1353
|
+
declare const EVIDENCE_CORE_VERSION = "evidence-core@1";
|
|
1354
|
+
/** Evidence source formats the core understands today (WI-17 adds trace.zip). */
|
|
1355
|
+
type EvidenceSource = ForensicsReport["source"];
|
|
1356
|
+
/** Normalized per-test runtime evidence (plan WI-2 field contract). */
|
|
1357
|
+
interface EvidenceRecord {
|
|
1358
|
+
/** Where this evidence came from (format identity). */
|
|
1359
|
+
source: EvidenceSource;
|
|
1360
|
+
/** Ingested artifact identity — the report path the records derive from. */
|
|
1361
|
+
artifact: string;
|
|
1362
|
+
/** Test identity: file + title (+ declaration line when known). */
|
|
1363
|
+
file: string;
|
|
1364
|
+
title: string;
|
|
1365
|
+
/** 1-based declaration line when the source carries one (JUnit: absent). */
|
|
1366
|
+
line?: number;
|
|
1367
|
+
/** Normalized execution status facts. */
|
|
1368
|
+
status: {
|
|
1369
|
+
/** Last attempt's outcome. */
|
|
1370
|
+
final: RunStatus;
|
|
1371
|
+
/** Failed at least once across attempts. */
|
|
1372
|
+
failed: boolean;
|
|
1373
|
+
/** Executed more than once. */
|
|
1374
|
+
retried: boolean;
|
|
1375
|
+
/** Passed only on attempt >= 2 (TRUE-FLAKE). */
|
|
1376
|
+
passedOnRetry: boolean;
|
|
1377
|
+
skipped: boolean;
|
|
1378
|
+
/** Final attempt timed out. */
|
|
1379
|
+
timedOut: boolean;
|
|
1380
|
+
};
|
|
1381
|
+
/** Number of attempts (retries = attempts − 1). */
|
|
1382
|
+
attempts: number;
|
|
1383
|
+
/** Total duration across attempts. */
|
|
1384
|
+
durationMs: number;
|
|
1385
|
+
/** Error messages, in report order. Empty: not captured by this source yet. */
|
|
1386
|
+
errors: string[];
|
|
1387
|
+
/** Attachment names/paths. Empty: not captured by this source yet (WI-17). */
|
|
1388
|
+
attachments: string[];
|
|
1389
|
+
/** Where the record came from and under which normalization contract. */
|
|
1390
|
+
provenance: {
|
|
1391
|
+
core: typeof EVIDENCE_CORE_VERSION;
|
|
1392
|
+
ingest: "mjolnir.forensics";
|
|
1393
|
+
};
|
|
1394
|
+
}
|
|
1395
|
+
//#endregion
|
|
1048
1396
|
//#region src/engine/provenance.d.ts
|
|
1049
1397
|
type FileProvenance = "unmarked" | "generated-marked" | "codegen-like";
|
|
1050
1398
|
/** Classify one file's provenance. Pure. */
|
|
@@ -1072,7 +1420,7 @@ interface IgnoreEntry {
|
|
|
1072
1420
|
ruleId: string;
|
|
1073
1421
|
files?: string[];
|
|
1074
1422
|
reason: string;
|
|
1075
|
-
/** ISO date;
|
|
1423
|
+
/** ISO date; omitted means the suppression has no expiry. */
|
|
1076
1424
|
expires?: string;
|
|
1077
1425
|
}
|
|
1078
1426
|
interface QADoctorConfig {
|
|
@@ -1298,6 +1646,12 @@ interface FileAnalysisResult {
|
|
|
1298
1646
|
parseFallbacks: number;
|
|
1299
1647
|
scanned: number;
|
|
1300
1648
|
analyzed: number;
|
|
1649
|
+
/**
|
|
1650
|
+
* Files that HAD an AST stage and lost it to the scan deadline, so they
|
|
1651
|
+
* were analyzed by regex alone. Zero for every adapter that declares no
|
|
1652
|
+
* `parseAst` — that is a capability envelope, not a downgrade.
|
|
1653
|
+
*/
|
|
1654
|
+
astFallbackFiles: number;
|
|
1301
1655
|
}
|
|
1302
1656
|
declare function runFileAnalysisPhase(findings: Finding[], testFiles: string[], workspace: Workspace, activeRules: UniversalRule[], hooks: ScanHooks, cache: ScanCache, rulesDigest: string, deadline: number, truncationReasons: Set<string>, declarationsByFile: Map<string, number>, fileProvenance: Array<{
|
|
1303
1657
|
path: string;
|
|
@@ -1313,6 +1667,12 @@ interface PostScanResult {
|
|
|
1313
1667
|
frameworks: ReturnType<typeof detectFrameworks>;
|
|
1314
1668
|
runtimeReportPath: string | undefined;
|
|
1315
1669
|
runtimeIncomplete: boolean;
|
|
1670
|
+
/**
|
|
1671
|
+
* The normalized evidence core (V5-011). Persisted rather than discarded,
|
|
1672
|
+
* so every post-ingest projection reads records instead of re-parsing a
|
|
1673
|
+
* report that may have changed underneath it.
|
|
1674
|
+
*/
|
|
1675
|
+
evidenceRecords: EvidenceRecord[];
|
|
1316
1676
|
/** Aggregate forensic classifications from the ingested runtime report. */
|
|
1317
1677
|
forensicVerdicts: ForensicVerdictSummary | undefined;
|
|
1318
1678
|
config: ReturnType<typeof loadConfig>["config"];
|
|
@@ -1339,6 +1699,14 @@ interface AssembleScanResultInput {
|
|
|
1339
1699
|
scopeUnrecognized: number;
|
|
1340
1700
|
parseFailed: number;
|
|
1341
1701
|
parseFallbacks?: number;
|
|
1702
|
+
/** Files that lost their AST stage to the scan deadline. See completion.ts. */
|
|
1703
|
+
astFallbackFiles?: number;
|
|
1704
|
+
/**
|
|
1705
|
+
* Reason-coded capability losses recorded during this scan's window. See
|
|
1706
|
+
* `src/engine/degradation-ledger.ts` for why the window is an index rather
|
|
1707
|
+
* than an ownership claim.
|
|
1708
|
+
*/
|
|
1709
|
+
degradations?: readonly DegradationCount[];
|
|
1342
1710
|
scanned: number;
|
|
1343
1711
|
analyzed?: number;
|
|
1344
1712
|
testFiles: string[];
|
|
@@ -1360,6 +1728,7 @@ interface AssembleScanResultInput {
|
|
|
1360
1728
|
frameworks: ReturnType<typeof detectFrameworks>;
|
|
1361
1729
|
runtimeReportPath: string | undefined;
|
|
1362
1730
|
runtimeIncomplete?: boolean;
|
|
1731
|
+
evidenceRecords?: EvidenceRecord[];
|
|
1363
1732
|
forensicVerdicts: ForensicVerdictSummary | undefined;
|
|
1364
1733
|
config: ReturnType<typeof loadConfig>["config"];
|
|
1365
1734
|
fileProvenance: Array<{
|
|
@@ -1393,7 +1762,7 @@ declare function runScan$1(args: CliArgs, hooks?: ScanHooks): Promise<ScanResult
|
|
|
1393
1762
|
* scripts/sync-sarif-version.cjs and guarded by the version-consistency
|
|
1394
1763
|
* spec. cli.ts re-exports this as CLI_VERSION.
|
|
1395
1764
|
*/
|
|
1396
|
-
declare const ENGINE_VERSION = "
|
|
1765
|
+
declare const ENGINE_VERSION = "5.0.0";
|
|
1397
1766
|
//#endregion
|
|
1398
1767
|
//#region src/cli-io.d.ts
|
|
1399
1768
|
/**
|
|
@@ -1575,11 +1944,17 @@ export declare function runReleaseTrustCommand(argv: string[], io?: {
|
|
|
1575
1944
|
* Entry point for `mjolnir business-case`.
|
|
1576
1945
|
*
|
|
1577
1946
|
* Flags:
|
|
1578
|
-
* --
|
|
1579
|
-
*
|
|
1580
|
-
*
|
|
1581
|
-
* --projected <months> Show projected savings over N months
|
|
1947
|
+
* --incident-cost <n> The cost of ONE false-green incident in your
|
|
1948
|
+
* organisation. Until you supply it, no dollar
|
|
1949
|
+
* figure is printed at all.
|
|
1582
1950
|
* --strict Include quarantine-tier findings
|
|
1951
|
+
*
|
|
1952
|
+
* `--history` and `--projected` are GONE. Both promised arithmetic this
|
|
1953
|
+
* tool cannot do: `--history` claimed to estimate from actual scan
|
|
1954
|
+
* improvements while reading no history at all, and `--projected` divided
|
|
1955
|
+
* the total by six and called the quotient a monthly rate. A flag that
|
|
1956
|
+
* does not do what its help says is worse than no flag, because the help
|
|
1957
|
+
* is the promise.
|
|
1583
1958
|
*/
|
|
1584
1959
|
export declare function runBusinessCaseCommand(argv: string[], io?: {
|
|
1585
1960
|
out: Output;
|
|
@@ -1623,7 +1998,7 @@ export declare function runPolicyCommand(argv: string[], io: {
|
|
|
1623
1998
|
export declare function runQuarantineCommand(argv: string[], io: {
|
|
1624
1999
|
out: Output;
|
|
1625
2000
|
err: Output;
|
|
1626
|
-
}):
|
|
2001
|
+
}): number;
|
|
1627
2002
|
//#endregion
|
|
1628
2003
|
//#region src/commands/analyze.d.ts
|
|
1629
2004
|
export declare function runAnalyzeCommand(argv: string[], io: {
|
|
@@ -1699,7 +2074,7 @@ export declare const MAX_DURATION_MS = 3600000;
|
|
|
1699
2074
|
export declare function parseArgs(argv: string[], onError?: (detail: UsageErrorDetail) => void): CliArgs | null;
|
|
1700
2075
|
/** Hand-rolled Levenshtein distance (plan M2: no new dependencies). */
|
|
1701
2076
|
export declare function levenshtein(a: string, b: string): number;
|
|
1702
|
-
/** Nearest known flags within distance
|
|
2077
|
+
/** Nearest known flags within distance ≤ 2, nearest first. */
|
|
1703
2078
|
export declare function nearestFlags(flag: string, max?: number): string[];
|
|
1704
2079
|
/**
|
|
1705
2080
|
* Friendly usage error (plan M2, exit 10 preserved): nearest-flag
|
|
@@ -1724,9 +2099,14 @@ export declare function parseArgsOrUsage(argv: string[], io: {
|
|
|
1724
2099
|
*/
|
|
1725
2100
|
export declare function validateScanTarget(target: string, err: Output): number | null;
|
|
1726
2101
|
/**
|
|
1727
|
-
* Exit-code decision for
|
|
1728
|
-
*
|
|
1729
|
-
*
|
|
2102
|
+
* Exit-code decision for findings only (audit H-7): the previously-dead
|
|
2103
|
+
* config.gate field selects which severities block. Advisory (E0) findings
|
|
2104
|
+
* never gate at any level.
|
|
2105
|
+
*
|
|
2106
|
+
* This is a findings-only view of the one exit matrix in `claim-evidence`.
|
|
2107
|
+
* Callers that have just finished an ANALYSIS must use `scanExitCode`
|
|
2108
|
+
* instead — this function cannot see `partial`, and a truncated scan with
|
|
2109
|
+
* zero findings is exactly the case that turns a bug into a green build.
|
|
1730
2110
|
*/
|
|
1731
2111
|
export declare function exitForFindings(findings: readonly Finding[], gate: "advisory" | "error" | "warning"): number;
|
|
1732
2112
|
/** Testable `ci install` handler. Returns the process exit code. */
|
|
@@ -1756,4 +2136,5 @@ export declare function runHelpCommand(argv: string[], io?: {
|
|
|
1756
2136
|
}): number;
|
|
1757
2137
|
export declare function isEntryPoint(): boolean;
|
|
1758
2138
|
//#endregion
|
|
1759
|
-
export { ENGINE_VERSION as CLI_VERSION, type CliArgs, type Output, type ScanHooks };
|
|
2139
|
+
export { ENGINE_VERSION as CLI_VERSION, type CliArgs, type Output, type ScanHooks };
|
|
2140
|
+
//# sourceMappingURL=cli.d.mts.map
|