@shrkcrft/boundaries 0.1.0-alpha.29 → 0.1.0-alpha.31
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/dist/baseline/compute-baseline.d.ts +8 -0
- package/dist/baseline/compute-baseline.d.ts.map +1 -1
- package/dist/baseline/compute-baseline.js +10 -8
- package/dist/baseline/diff-baseline.d.ts +28 -0
- package/dist/baseline/diff-baseline.d.ts.map +1 -1
- package/dist/baseline/diff-baseline.js +29 -0
- package/dist/evaluate/boundary-unit-finding.d.ts +10 -0
- package/dist/evaluate/boundary-unit-finding.d.ts.map +1 -0
- package/dist/evaluate/boundary-unit-finding.js +21 -0
- package/dist/evaluate/boundary-unit-kind.d.ts +7 -0
- package/dist/evaluate/boundary-unit-kind.d.ts.map +1 -0
- package/dist/evaluate/boundary-unit-kind.js +14 -0
- package/dist/evaluate/evaluate-boundaries.d.ts +230 -3
- package/dist/evaluate/evaluate-boundaries.d.ts.map +1 -1
- package/dist/evaluate/evaluate-boundaries.js +481 -53
- package/dist/evaluate/i-boundary-rule-settle-input.d.ts +27 -0
- package/dist/evaluate/i-boundary-rule-settle-input.d.ts.map +1 -0
- package/dist/evaluate/i-boundary-rule-settle-input.js +1 -0
- package/dist/evaluate/i-boundary-rule-settlement.d.ts +23 -0
- package/dist/evaluate/i-boundary-rule-settlement.d.ts.map +1 -0
- package/dist/evaluate/i-boundary-rule-settlement.js +1 -0
- package/dist/evaluate/i-boundary-unit-finding.d.ts +22 -0
- package/dist/evaluate/i-boundary-unit-finding.d.ts.map +1 -0
- package/dist/evaluate/i-boundary-unit-finding.js +1 -0
- package/dist/evaluate/settle-boundary-rule.d.ts +23 -0
- package/dist/evaluate/settle-boundary-rule.d.ts.map +1 -0
- package/dist/evaluate/settle-boundary-rule.js +73 -0
- package/dist/evaluate/with-boundary-rule-settlement.d.ts +11 -0
- package/dist/evaluate/with-boundary-rule-settlement.d.ts.map +1 -0
- package/dist/evaluate/with-boundary-rule-settlement.js +44 -0
- package/dist/extract/code-zones.d.ts +95 -3
- package/dist/extract/code-zones.d.ts.map +1 -1
- package/dist/extract/code-zones.js +313 -4
- package/dist/extract/extract-tokens.d.ts +49 -1
- package/dist/extract/extract-tokens.d.ts.map +1 -1
- package/dist/extract/extract-tokens.js +283 -25
- package/dist/extract/i-labeled-source.d.ts +12 -0
- package/dist/extract/i-labeled-source.d.ts.map +1 -0
- package/dist/extract/i-labeled-source.js +1 -0
- package/dist/extract/import-edges.d.ts +50 -0
- package/dist/extract/import-edges.d.ts.map +1 -0
- package/dist/extract/import-edges.js +170 -0
- package/dist/extract/inspect-source.d.ts +38 -3
- package/dist/extract/inspect-source.d.ts.map +1 -1
- package/dist/extract/inspect-source.js +56 -8
- package/dist/extract/parse-imports.d.ts +80 -0
- package/dist/extract/parse-imports.d.ts.map +1 -0
- package/dist/extract/parse-imports.js +254 -0
- package/dist/extract/scan-literals.d.ts +12 -1
- package/dist/extract/scan-literals.d.ts.map +1 -1
- package/dist/extract/scan-literals.js +15 -1
- package/dist/extract/source-liveness-request.d.ts +24 -0
- package/dist/extract/source-liveness-request.d.ts.map +1 -0
- package/dist/extract/source-liveness-request.js +45 -0
- package/dist/generated/check-provenance.d.ts +20 -2
- package/dist/generated/check-provenance.d.ts.map +1 -1
- package/dist/generated/check-provenance.js +27 -6
- package/dist/generated/read-regen-tree.d.ts +16 -0
- package/dist/generated/read-regen-tree.d.ts.map +1 -0
- package/dist/generated/read-regen-tree.js +61 -0
- package/dist/generated/scan-generated.d.ts +57 -3
- package/dist/generated/scan-generated.d.ts.map +1 -1
- package/dist/generated/scan-generated.js +111 -11
- package/dist/index.d.ts +51 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +54 -0
- package/dist/model/boundary-intended-empty-line.d.ts +10 -0
- package/dist/model/boundary-intended-empty-line.d.ts.map +1 -0
- package/dist/model/boundary-intended-empty-line.js +11 -0
- package/dist/model/boundary-markable-list.d.ts +15 -0
- package/dist/model/boundary-markable-list.d.ts.map +1 -0
- package/dist/model/boundary-markable-list.js +15 -0
- package/dist/model/boundary-rule-input-keys.d.ts +11 -0
- package/dist/model/boundary-rule-input-keys.d.ts.map +1 -0
- package/dist/model/boundary-rule-input-keys.js +29 -0
- package/dist/model/boundary-rule-input.d.ts +23 -0
- package/dist/model/boundary-rule-input.d.ts.map +1 -0
- package/dist/model/boundary-rule-input.js +1 -0
- package/dist/model/boundary-rule-key-problems.d.ts +11 -0
- package/dist/model/boundary-rule-key-problems.d.ts.map +1 -0
- package/dist/model/boundary-rule-key-problems.js +36 -0
- package/dist/model/boundary-rule-marker-problems.d.ts +26 -0
- package/dist/model/boundary-rule-marker-problems.d.ts.map +1 -0
- package/dist/model/boundary-rule-marker-problems.js +94 -0
- package/dist/model/boundary-rule-scope.d.ts +88 -0
- package/dist/model/boundary-rule-scope.d.ts.map +1 -0
- package/dist/model/boundary-rule-scope.js +175 -0
- package/dist/model/boundary-rule.d.ts +120 -5
- package/dist/model/boundary-rule.d.ts.map +1 -1
- package/dist/model/boundary-rule.js +148 -1
- package/dist/model/boundary-unit-problem-issue.d.ts +9 -0
- package/dist/model/boundary-unit-problem-issue.d.ts.map +1 -0
- package/dist/model/boundary-unit-problem-issue.js +16 -0
- package/dist/model/normalize-boundary-rule.d.ts +21 -0
- package/dist/model/normalize-boundary-rule.d.ts.map +1 -0
- package/dist/model/normalize-boundary-rule.js +62 -0
- package/dist/policy/evaluate-policy.d.ts +80 -3
- package/dist/policy/evaluate-policy.d.ts.map +1 -1
- package/dist/policy/evaluate-policy.js +152 -19
- package/dist/policy/i-policy-rule-liveness.d.ts +15 -0
- package/dist/policy/i-policy-rule-liveness.d.ts.map +1 -0
- package/dist/policy/i-policy-rule-liveness.js +1 -0
- package/dist/policy/run-policy.d.ts +1 -1
- package/dist/policy/run-policy.d.ts.map +1 -1
- package/dist/policy/run-policy.js +171 -21
- package/dist/registry/load-boundary-rules.d.ts +29 -1
- package/dist/registry/load-boundary-rules.d.ts.map +1 -1
- package/dist/registry/load-boundary-rules.js +38 -8
- package/dist/scan/glob.d.ts +90 -0
- package/dist/scan/glob.d.ts.map +1 -1
- package/dist/scan/glob.js +205 -0
- package/dist/scan/i-glob-unit-measure.d.ts +22 -0
- package/dist/scan/i-glob-unit-measure.d.ts.map +1 -0
- package/dist/scan/i-glob-unit-measure.js +1 -0
- package/dist/scan/import-pattern.d.ts +109 -0
- package/dist/scan/import-pattern.d.ts.map +1 -0
- package/dist/scan/import-pattern.js +191 -0
- package/dist/scan/node-builtin-package-names.d.ts +13 -0
- package/dist/scan/node-builtin-package-names.d.ts.map +1 -0
- package/dist/scan/node-builtin-package-names.js +25 -0
- package/dist/scan/scan-imports.d.ts +36 -3
- package/dist/scan/scan-imports.d.ts.map +1 -1
- package/dist/scan/scan-imports.js +114 -45
- package/dist/util/blank-run-hazard-finding.d.ts +34 -0
- package/dist/util/blank-run-hazard-finding.d.ts.map +1 -0
- package/dist/util/blank-run-hazard-finding.js +1 -0
- package/dist/util/blank-run-hazard.d.ts +29 -0
- package/dist/util/blank-run-hazard.d.ts.map +1 -0
- package/dist/util/blank-run-hazard.js +450 -0
- package/dist/util/dead-glob-units.d.ts +46 -0
- package/dist/util/dead-glob-units.d.ts.map +1 -0
- package/dist/util/dead-glob-units.js +116 -0
- package/dist/util/glob-list-liveness-input.d.ts +31 -0
- package/dist/util/glob-list-liveness-input.d.ts.map +1 -0
- package/dist/util/glob-list-liveness-input.js +65 -0
- package/dist/util/i-dead-glob-unit.d.ts +24 -0
- package/dist/util/i-dead-glob-unit.d.ts.map +1 -0
- package/dist/util/i-dead-glob-unit.js +1 -0
- package/dist/util/i-glob-list-units.d.ts +25 -0
- package/dist/util/i-glob-list-units.d.ts.map +1 -0
- package/dist/util/i-glob-list-units.js +1 -0
- package/dist/util/i-glob-liveness-list.d.ts +23 -0
- package/dist/util/i-glob-liveness-list.d.ts.map +1 -0
- package/dist/util/i-glob-liveness-list.js +1 -0
- package/dist/util/i-glob-liveness-request.d.ts +11 -0
- package/dist/util/i-glob-liveness-request.d.ts.map +1 -0
- package/dist/util/i-glob-liveness-request.js +1 -0
- package/dist/util/i-glob-negation.d.ts +13 -0
- package/dist/util/i-glob-negation.d.ts.map +1 -0
- package/dist/util/i-glob-negation.js +1 -0
- package/dist/util/matched-files.d.ts +22 -0
- package/dist/util/matched-files.d.ts.map +1 -0
- package/dist/util/matched-files.js +1 -0
- package/dist/util/negation-cause.d.ts +15 -0
- package/dist/util/negation-cause.d.ts.map +1 -0
- package/dist/util/negation-cause.js +21 -0
- package/dist/util/plane-scan-exclude-dirs.d.ts +17 -0
- package/dist/util/plane-scan-exclude-dirs.d.ts.map +1 -0
- package/dist/util/plane-scan-exclude-dirs.js +22 -0
- package/dist/util/read-glob-list-liveness.d.ts +20 -0
- package/dist/util/read-glob-list-liveness.d.ts.map +1 -0
- package/dist/util/read-glob-list-liveness.js +20 -0
- package/dist/util/read-scope-coverage.d.ts +90 -0
- package/dist/util/read-scope-coverage.d.ts.map +1 -0
- package/dist/util/read-scope-coverage.js +173 -0
- package/dist/util/read-scope.d.ts +14 -0
- package/dist/util/read-scope.d.ts.map +1 -0
- package/dist/util/read-scope.js +1 -0
- package/dist/util/read-selected-files.d.ts +16 -0
- package/dist/util/read-selected-files.d.ts.map +1 -0
- package/dist/util/read-selected-files.js +25 -0
- package/dist/util/settle-glob-lists.d.ts +12 -0
- package/dist/util/settle-glob-lists.d.ts.map +1 -0
- package/dist/util/settle-glob-lists.js +13 -0
- package/dist/util/unread-file-reason.d.ts +26 -0
- package/dist/util/unread-file-reason.d.ts.map +1 -0
- package/dist/util/unread-file-reason.js +26 -0
- package/dist/util/unread-file.d.ts +10 -0
- package/dist/util/unread-file.d.ts.map +1 -0
- package/dist/util/unread-file.js +1 -0
- package/dist/util/walk-files.d.ts +90 -7
- package/dist/util/walk-files.d.ts.map +1 -1
- package/dist/util/walk-files.js +206 -19
- package/dist/wiring/evaluate-wiring.d.ts +88 -7
- package/dist/wiring/evaluate-wiring.d.ts.map +1 -1
- package/dist/wiring/evaluate-wiring.js +276 -16
- package/dist/wiring/explain-wiring.d.ts +56 -14
- package/dist/wiring/explain-wiring.d.ts.map +1 -1
- package/dist/wiring/explain-wiring.js +136 -10
- package/dist/wiring/i-idiom-role-coverage.d.ts +24 -0
- package/dist/wiring/i-idiom-role-coverage.d.ts.map +1 -0
- package/dist/wiring/i-idiom-role-coverage.js +1 -0
- package/dist/wiring/i-registration-query-verdict.d.ts +38 -0
- package/dist/wiring/i-registration-query-verdict.d.ts.map +1 -0
- package/dist/wiring/i-registration-query-verdict.js +1 -0
- package/dist/wiring/i-registration-roles.d.ts +71 -0
- package/dist/wiring/i-registration-roles.d.ts.map +1 -0
- package/dist/wiring/i-registration-roles.js +1 -0
- package/dist/wiring/measure-idiom-role-coverage.d.ts +12 -0
- package/dist/wiring/measure-idiom-role-coverage.d.ts.map +1 -0
- package/dist/wiring/measure-idiom-role-coverage.js +20 -0
- package/dist/wiring/measure-registration-roles.d.ts +25 -0
- package/dist/wiring/measure-registration-roles.d.ts.map +1 -0
- package/dist/wiring/measure-registration-roles.js +124 -0
- package/dist/wiring/plan-wiring-fix.d.ts +16 -1
- package/dist/wiring/plan-wiring-fix.d.ts.map +1 -1
- package/dist/wiring/plan-wiring-fix.js +177 -4
- package/dist/wiring/registration-graph.d.ts +13 -1
- package/dist/wiring/registration-graph.d.ts.map +1 -1
- package/dist/wiring/registration-graph.js +22 -6
- package/dist/wiring/registration-query-verdict.d.ts +23 -0
- package/dist/wiring/registration-query-verdict.d.ts.map +1 -0
- package/dist/wiring/registration-query-verdict.js +118 -0
- package/dist/wiring/registry-query.d.ts +9 -1
- package/dist/wiring/registry-query.d.ts.map +1 -1
- package/dist/wiring/registry-query.js +17 -6
- package/dist/wiring/scan-wiring-files.d.ts +5 -3
- package/dist/wiring/scan-wiring-files.d.ts.map +1 -1
- package/dist/wiring/scan-wiring-files.js +55 -14
- package/dist/wiring/sink-imports.d.ts +95 -0
- package/dist/wiring/sink-imports.d.ts.map +1 -0
- package/dist/wiring/sink-imports.js +124 -0
- package/dist/wiring/trace-literal.d.ts +6 -0
- package/dist/wiring/trace-literal.d.ts.map +1 -1
- package/dist/wiring/trace-literal.js +5 -2
- package/dist/wiring/wiring-labeled-sources.d.ts +12 -0
- package/dist/wiring/wiring-labeled-sources.d.ts.map +1 -0
- package/dist/wiring/wiring-labeled-sources.js +20 -0
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"explain-wiring.d.ts","sourceRoot":"","sources":["../../src/wiring/explain-wiring.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"explain-wiring.d.ts","sourceRoot":"","sources":["../../src/wiring/explain-wiring.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,26 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { coverageAcceptance, coverageShortfall, normalizeWiringRule, settleRuleStatus, } from '@shrkcrft/core';
|
|
2
|
+
import { sourceLivenessRequest } from "../extract/source-liveness-request.js";
|
|
3
|
+
import { globListSelects } from "../scan/glob.js";
|
|
4
|
+
import { globListUnits } from "../util/dead-glob-units.js";
|
|
5
|
+
import { settleGlobLists } from "../util/settle-glob-lists.js";
|
|
2
6
|
import { readMatchingFiles } from "../util/walk-files.js";
|
|
7
|
+
import { unreadMatching } from "../util/read-scope-coverage.js";
|
|
3
8
|
import { collectSourceSites, evaluateWiring, registeredSources, wiringGlobsOf, wiringSourceSide, } from "./evaluate-wiring.js";
|
|
9
|
+
import { wiringLabeledSources } from "./wiring-labeled-sources.js";
|
|
4
10
|
export const WIRING_EXPLAIN_SCHEMA = 'sharkcraft.wiring-explain/v1';
|
|
11
|
+
/**
|
|
12
|
+
* The zone the registered side extracted under — only when EVERY sink agrees on
|
|
13
|
+
* a non-default one. Reporting one sink's zone as the side's would be a claim
|
|
14
|
+
* the explain cannot back.
|
|
15
|
+
*/
|
|
16
|
+
function registeredScanZone(sources) {
|
|
17
|
+
if (sources.length === 0)
|
|
18
|
+
return undefined;
|
|
19
|
+
const first = sources[0].scan ?? 'all';
|
|
20
|
+
if (first === 'all')
|
|
21
|
+
return undefined;
|
|
22
|
+
return sources.every((s) => (s.scan ?? 'all') === first) ? first : undefined;
|
|
23
|
+
}
|
|
5
24
|
function sortSites(sites) {
|
|
6
25
|
return [...sites].sort((a, b) => a.file.localeCompare(b.file) || a.line - b.line || a.token.localeCompare(b.token));
|
|
7
26
|
}
|
|
@@ -14,19 +33,49 @@ function sortSites(sites) {
|
|
|
14
33
|
* committing a rule. The diff/verdict reuse {@link evaluateWiring} so they match
|
|
15
34
|
* the gate exactly (incl. `groupBy` membership). Never throws.
|
|
16
35
|
*/
|
|
17
|
-
|
|
36
|
+
/**
|
|
37
|
+
* The extractor a rule's registered side resolved from — only when EVERY sink
|
|
38
|
+
* shares it. A union of sinks where one is shared and another is inline has no
|
|
39
|
+
* single answer, and naming just one would be a claim the config does not make.
|
|
40
|
+
*/
|
|
41
|
+
function registeredExtractorRef(rule) {
|
|
42
|
+
const sinks = Array.isArray(rule.registered)
|
|
43
|
+
? rule.registered
|
|
44
|
+
: rule.registered
|
|
45
|
+
? [rule.registered]
|
|
46
|
+
: [];
|
|
47
|
+
if (sinks.length === 0)
|
|
48
|
+
return undefined;
|
|
49
|
+
const first = sinks[0].$use;
|
|
50
|
+
return first !== undefined && sinks.every((s) => s.$use === first) ? first : undefined;
|
|
51
|
+
}
|
|
52
|
+
export function explainWiring(projectRoot, authored, options = {}) {
|
|
53
|
+
// The engine entry normalises idempotently (round 13): a loaded rule comes
|
|
54
|
+
// back equal; a hand-built `{ pattern, expectEmpty }` entry (`wiring test`,
|
|
55
|
+
// `gates try`) becomes a glob plus a marker. A MALFORMED entry is reported
|
|
56
|
+
// the way the engine reports it — a misconfigured rule — and never reaches
|
|
57
|
+
// a glob reader (it crashed `wiring test` with `glob.startsWith is not a
|
|
58
|
+
// function`).
|
|
59
|
+
const normalized = normalizeWiringRule(authored);
|
|
60
|
+
if (!normalized.ok)
|
|
61
|
+
return misconfiguredExplain(authored, evaluateWiring([authored], () => []));
|
|
62
|
+
const rule = normalized.value;
|
|
63
|
+
const excludeDirs = options.excludeDirs ?? [];
|
|
18
64
|
const sourceSide = wiringSourceSide(rule);
|
|
19
65
|
// For a chain, the reported "registered" side is the LAST hop (the far end).
|
|
20
66
|
const sinkSources = rule.chain && rule.chain.length >= 2
|
|
21
67
|
? [rule.chain[rule.chain.length - 1]]
|
|
22
68
|
: registeredSources(rule.registered);
|
|
23
69
|
const allGlobs = [...new Set(wiringGlobsOf(rule))];
|
|
24
|
-
const
|
|
25
|
-
const entries = [...
|
|
70
|
+
const matched = readMatchingFiles(projectRoot, allGlobs, new Set(options.excludeDirs ?? []));
|
|
71
|
+
const entries = [...matched.files.entries()].map(([path, content]) => ({
|
|
26
72
|
path,
|
|
27
73
|
content,
|
|
28
74
|
}));
|
|
29
|
-
const filesFor = (source) => entries.filter((f) =>
|
|
75
|
+
const filesFor = (source) => entries.filter((f) => globListSelects(f.path, source.files ?? []));
|
|
76
|
+
// The same unread list the check hands its engine, so the explain's coverage
|
|
77
|
+
// (read off the engine, never recomputed) names the same unread files.
|
|
78
|
+
const unreadFor = (source) => unreadMatching(matched.unread, source.files ?? []);
|
|
30
79
|
const declaredFiles = sourceSide ? filesFor(sourceSide) : [];
|
|
31
80
|
const declaredRes = sourceSide
|
|
32
81
|
? collectSourceSites(sourceSide, declaredFiles)
|
|
@@ -34,6 +83,7 @@ export function explainWiring(projectRoot, rule, options = {}) {
|
|
|
34
83
|
const registeredFiles = new Set();
|
|
35
84
|
const registeredSites = [];
|
|
36
85
|
let registeredError;
|
|
86
|
+
let registeredBlanked = 0;
|
|
37
87
|
for (const source of sinkSources) {
|
|
38
88
|
const files = filesFor(source);
|
|
39
89
|
for (const f of files)
|
|
@@ -41,15 +91,40 @@ export function explainWiring(projectRoot, rule, options = {}) {
|
|
|
41
91
|
const res = collectSourceSites(source, files);
|
|
42
92
|
if (res.error && !registeredError)
|
|
43
93
|
registeredError = res.error;
|
|
94
|
+
if (res.blankedChars !== undefined)
|
|
95
|
+
registeredBlanked += res.blankedChars;
|
|
44
96
|
registeredSites.push(...res.sites);
|
|
45
97
|
}
|
|
46
|
-
// Canonical diff + counts + verdict from the gate engine (same groupBy logic)
|
|
47
|
-
|
|
98
|
+
// Canonical diff + counts + verdict from the gate engine (same groupBy logic),
|
|
99
|
+
// handed the SAME hooks `runWiring` gives it (round 13): which negations
|
|
100
|
+
// emptied a source, and every source's glob units settled with their
|
|
101
|
+
// `expectEmpty` markers (`sourceLivenessRequest` over the engine's side
|
|
102
|
+
// labels). An explained rule is therefore accepted, skipped or failed exactly
|
|
103
|
+
// as `check wiring` settles it — a planned rule the check accepts used to
|
|
104
|
+
// explain as "SKIPPED … Verdict: errors" (`check wiring --explain` exit 1,
|
|
105
|
+
// `gates try` 2).
|
|
106
|
+
const walked = entries.map((f) => f.path);
|
|
107
|
+
const unitsOf = (globs) => globListUnits(walked, matched.unread, globs);
|
|
108
|
+
const report = evaluateWiring([rule], filesFor, {}, unreadFor, (source) => {
|
|
109
|
+
const units = unitsOf(source.files ?? []);
|
|
110
|
+
return units.allExcluded ? units.negations : undefined;
|
|
111
|
+
}, (r) => settleGlobLists(sourceLivenessRequest(projectRoot, wiringLabeledSources(r), excludeDirs, r.id, unitsOf)));
|
|
48
112
|
const ruleResult = report.rules[0];
|
|
49
113
|
const byDirection = (d) => sortSites((ruleResult?.violations ?? [])
|
|
50
114
|
.filter((v) => v.direction === d)
|
|
51
115
|
.map((v) => ({ token: v.token, file: v.file, line: v.line })));
|
|
52
116
|
const skip = report.skipped[0];
|
|
117
|
+
// The engine's coverage, read — never recomputed — and settled with the SAME
|
|
118
|
+
// core functions the gate envelope uses: a `passed` rule with a shortfall is
|
|
119
|
+
// `partial`, and a non-`errors` verdict over a shortfall is `not-verified`.
|
|
120
|
+
const coverage = ruleResult?.coverage ?? {
|
|
121
|
+
unit: 'declared tokens',
|
|
122
|
+
expected: 0,
|
|
123
|
+
examined: 0,
|
|
124
|
+
reason: 'the rule did not run',
|
|
125
|
+
};
|
|
126
|
+
const shortfall = coverageShortfall(coverage);
|
|
127
|
+
const acceptance = coverageAcceptance(coverage);
|
|
53
128
|
return {
|
|
54
129
|
schema: WIRING_EXPLAIN_SCHEMA,
|
|
55
130
|
ruleId: rule.id,
|
|
@@ -63,20 +138,71 @@ export function explainWiring(projectRoot, rule, options = {}) {
|
|
|
63
138
|
distinctCount: ruleResult?.declaredCount ?? 0,
|
|
64
139
|
filesScanned: declaredFiles.length,
|
|
65
140
|
...(declaredRes.error ? { error: declaredRes.error } : {}),
|
|
141
|
+
...(rule.declared?.$use ? { viaExtractor: rule.declared.$use } : {}),
|
|
142
|
+
...(sourceSide?.scan && sourceSide.scan !== 'all'
|
|
143
|
+
? { scan: sourceSide.scan, blankedChars: declaredRes.blankedChars ?? 0 }
|
|
144
|
+
: {}),
|
|
66
145
|
},
|
|
67
146
|
registered: {
|
|
68
147
|
sites: sortSites(registeredSites),
|
|
69
148
|
distinctCount: ruleResult?.registeredCount ?? 0,
|
|
70
149
|
filesScanned: registeredFiles.size,
|
|
71
150
|
...(registeredError ? { error: registeredError } : {}),
|
|
151
|
+
...(registeredExtractorRef(rule) ? { viaExtractor: registeredExtractorRef(rule) } : {}),
|
|
152
|
+
...(registeredScanZone(sinkSources)
|
|
153
|
+
? { scan: registeredScanZone(sinkSources), blankedChars: registeredBlanked }
|
|
154
|
+
: {}),
|
|
72
155
|
},
|
|
73
156
|
declaredNotRegistered: byDirection('declared-missing'),
|
|
74
|
-
|
|
157
|
+
// Read, never recomputed: the engine's ONE registered-minus-declared set —
|
|
158
|
+
// parity's violations and subset's coverage shortfall are the same set.
|
|
159
|
+
registeredNotDeclared: sortSites((ruleResult?.registeredOnly ?? []).map((s) => ({ token: s.token, file: s.file, line: s.line }))),
|
|
75
160
|
overlap: byDirection('overlap'),
|
|
76
161
|
...(ruleResult?.hops ? { hops: ruleResult.hops } : {}),
|
|
77
|
-
status: ruleResult?.status ?? 'error',
|
|
162
|
+
status: settleRuleStatus(ruleResult?.status ?? 'error', coverage),
|
|
78
163
|
...(skip ? { skipReason: skip.reason } : {}),
|
|
79
|
-
verdict: report.verdict,
|
|
164
|
+
verdict: report.verdict !== 'errors' && shortfall !== undefined ? 'not-verified' : report.verdict,
|
|
165
|
+
coverage,
|
|
166
|
+
...(shortfall !== undefined ? { shortfall } : {}),
|
|
167
|
+
...(acceptance !== undefined ? { acceptance } : {}),
|
|
168
|
+
...(ruleResult?.unitAcceptance !== undefined ? { unitAcceptance: ruleResult.unitAcceptance } : {}),
|
|
169
|
+
...(ruleResult?.units !== undefined ? { units: ruleResult.units } : {}),
|
|
170
|
+
...(ruleResult?.unitLiveness !== undefined ? { unitLiveness: ruleResult.unitLiveness } : {}),
|
|
171
|
+
diagnostics: report.diagnostics,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* The explain of a rule whose markable list is malformed (round 13): the
|
|
176
|
+
* engine's own misconfigured result (`evaluateWiring` normalises at entry and
|
|
177
|
+
* reports the bad entry), with empty sides — no glob reader ever sees it.
|
|
178
|
+
*/
|
|
179
|
+
function misconfiguredExplain(rule, report) {
|
|
180
|
+
const ruleResult = report.rules[0];
|
|
181
|
+
const coverage = ruleResult?.coverage ?? {
|
|
182
|
+
unit: 'declared tokens',
|
|
183
|
+
expected: 0,
|
|
184
|
+
examined: 0,
|
|
185
|
+
reason: 'the rule did not run',
|
|
186
|
+
};
|
|
187
|
+
const shortfall = coverageShortfall(coverage);
|
|
188
|
+
const error = report.diagnostics[0] ?? ruleResult?.error ?? 'the rule is misconfigured';
|
|
189
|
+
return {
|
|
190
|
+
schema: WIRING_EXPLAIN_SCHEMA,
|
|
191
|
+
ruleId: rule.id,
|
|
192
|
+
...(rule.description ? { description: rule.description } : {}),
|
|
193
|
+
mode: rule.mode ?? 'subset',
|
|
194
|
+
registeredMode: rule.registeredMode ?? 'union',
|
|
195
|
+
...(rule.groupBy ? { groupBy: rule.groupBy } : {}),
|
|
196
|
+
severity: rule.severity ?? 'error',
|
|
197
|
+
declared: { sites: [], distinctCount: 0, filesScanned: 0, error },
|
|
198
|
+
registered: { sites: [], distinctCount: 0, filesScanned: 0 },
|
|
199
|
+
declaredNotRegistered: [],
|
|
200
|
+
registeredNotDeclared: [],
|
|
201
|
+
overlap: [],
|
|
202
|
+
status: settleRuleStatus(ruleResult?.status ?? 'error', coverage),
|
|
203
|
+
verdict: report.verdict !== 'errors' && shortfall !== undefined ? 'not-verified' : report.verdict,
|
|
204
|
+
coverage,
|
|
205
|
+
...(shortfall !== undefined ? { shortfall } : {}),
|
|
80
206
|
diagnostics: report.diagnostics,
|
|
81
207
|
};
|
|
82
208
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { IVerdictCoverage } from '@shrkcrft/core';
|
|
2
|
+
/**
|
|
3
|
+
* One registration idiom's role coverage, as the registration-graph QUERIES
|
|
4
|
+
* fold it (round 13, P4): `wiring unprovided | orphans`, finish's unprovided
|
|
5
|
+
* sub-gate and MCP `get_wiring_graph`. Measured by THE role authority
|
|
6
|
+
* (`measureRegistrationRoles`, the one `gates check` / `gates coverage` read),
|
|
7
|
+
* so an absence query can no longer print a ✓ over a declared / provided /
|
|
8
|
+
* consumed role that matched no file.
|
|
9
|
+
*/
|
|
10
|
+
export interface IIdiomRoleCoverage {
|
|
11
|
+
/** The idiom's `name` — the subject its records are settled under. */
|
|
12
|
+
readonly idiom: string;
|
|
13
|
+
/** `measureRegistrationRoles(...).coverage` — `examined N of 3 roles`, or the read-scope record. */
|
|
14
|
+
readonly coverage: IVerdictCoverage;
|
|
15
|
+
/** Its settle record B (`IRegistrationRoles.unitAcceptance`), when a role unit is marked expectEmpty. */
|
|
16
|
+
readonly unitAcceptance?: IVerdictCoverage;
|
|
17
|
+
/**
|
|
18
|
+
* A role left a matched file unread, so {@link coverage} is the read-scope
|
|
19
|
+
* record — the graph's own read-scope record names the same files, so a
|
|
20
|
+
* query that carries that record drops this one rather than name them twice.
|
|
21
|
+
*/
|
|
22
|
+
readonly readGap: boolean;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=i-idiom-role-coverage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i-idiom-role-coverage.d.ts","sourceRoot":"","sources":["../../src/wiring/i-idiom-role-coverage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEvD;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAkB;IACjC,sEAAsE;IACtE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,oGAAoG;IACpG,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IACpC,yGAAyG;IACzG,QAAQ,CAAC,cAAc,CAAC,EAAE,gBAAgB,CAAC;IAC3C;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { IVerdictCoverage } from '@shrkcrft/core';
|
|
2
|
+
import type { IUnreadFile } from '../util/unread-file.js';
|
|
3
|
+
/**
|
|
4
|
+
* What a registration-graph ABSENCE query proves over what the graph READ.
|
|
5
|
+
*
|
|
6
|
+
* `wiring unprovided` claims "no provider anywhere"; `wiring orphans` claims
|
|
7
|
+
* "no consumer anywhere". Both are claims about files the graph never saw
|
|
8
|
+
* when an idiom glob matched a file over the read cap. So an absence whose
|
|
9
|
+
* missing site could sit in such a file is demoted from a finding to
|
|
10
|
+
* `unproven`, and the demoted tokens are named in the coverage. The same rule
|
|
11
|
+
* the registry plane applies: only a positive finding survives an incomplete
|
|
12
|
+
* inventory.
|
|
13
|
+
*/
|
|
14
|
+
export interface IRegistrationQueryVerdict<T extends {
|
|
15
|
+
readonly token: string;
|
|
16
|
+
}> {
|
|
17
|
+
/** Absences the read proves: no unread file could hold the missing site. */
|
|
18
|
+
readonly findings: readonly T[];
|
|
19
|
+
/**
|
|
20
|
+
* Candidates an unread file could refute: the missing role's globs match a
|
|
21
|
+
* file the reader did not read. Never a finding, and never a pass.
|
|
22
|
+
*/
|
|
23
|
+
readonly unproven: readonly T[];
|
|
24
|
+
/**
|
|
25
|
+
* What to settle against: the graph's read scope (the unread files, named),
|
|
26
|
+
* every idiom's ROLE records (round 13, P4 — `examined 2 of 3 roles …
|
|
27
|
+
* declared (0 files)`, plus any expectEmpty acceptance; subject = the
|
|
28
|
+
* idiom), and, when candidates were demoted, the demoted tokens. Never
|
|
29
|
+
* empty when an idiom was measured: a role that examined nothing is a
|
|
30
|
+
* shortfall here exactly as on `gates check`.
|
|
31
|
+
*/
|
|
32
|
+
readonly coverage: readonly IVerdictCoverage[];
|
|
33
|
+
/** Core's `coverageShortfall` of each record, in order. */
|
|
34
|
+
readonly shortfalls: readonly string[];
|
|
35
|
+
/** Every file the idioms matched that the reader did not read. */
|
|
36
|
+
readonly unread: readonly IUnreadFile[];
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=i-registration-query-verdict.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i-registration-query-verdict.d.ts","sourceRoot":"","sources":["../../src/wiring/i-registration-query-verdict.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAE1D;;;;;;;;;;GAUG;AACH,MAAM,WAAW,yBAAyB,CAAC,CAAC,SAAS;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE;IAC7E,4EAA4E;IAC5E,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC,EAAE,CAAC;IAChC;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC,EAAE,CAAC;IAChC;;;;;;;OAOG;IACH,QAAQ,CAAC,QAAQ,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAC/C,2DAA2D;IAC3D,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,kEAAkE;IAClE,QAAQ,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,CAAC;CACzC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { ISettledUnitLiveness, IVerdictCoverage } from '@shrkcrft/core';
|
|
2
|
+
import type { ISourceInspection } from '../extract/inspect-source.js';
|
|
3
|
+
/**
|
|
4
|
+
* What each of a registration idiom's three roles extracted from the live tree:
|
|
5
|
+
* THE answer to "is this idiom empty?" and "which of its roles examined
|
|
6
|
+
* nothing?".
|
|
7
|
+
*
|
|
8
|
+
* `gates check` (the violation check) and `gates coverage` (the stale-selector
|
|
9
|
+
* detector) both read this one measurement. Before it existed they answered
|
|
10
|
+
* "empty" differently: check keyed on the union of every role's tokens, while
|
|
11
|
+
* coverage keyed on the declared role. So a failOnEmpty idiom whose declared
|
|
12
|
+
* glob had moved FAILED coverage while check printed a ✓ over the same tree.
|
|
13
|
+
*
|
|
14
|
+
* Round 13 (P4): it lives in @shrkcrft/boundaries (it moved down from the CLI's
|
|
15
|
+
* gates, which re-export it) so the registration-graph QUERIES read it too —
|
|
16
|
+
* `wiring unprovided | orphans`, finish's unprovided sub-gate and MCP
|
|
17
|
+
* `get_wiring_graph`, which cannot import the CLI. They printed a ✓ over an
|
|
18
|
+
* idiom whose declared role matched no file while `gates check` said NOT
|
|
19
|
+
* VERIFIED on the same tree.
|
|
20
|
+
*/
|
|
21
|
+
export interface IRegistrationRoles {
|
|
22
|
+
/** The DECLARED role, the idiom's primary selector. Its ids are what a selfTest asserts on. */
|
|
23
|
+
readonly declared: ISourceInspection;
|
|
24
|
+
readonly provided: ISourceInspection;
|
|
25
|
+
readonly consumed: ISourceInspection;
|
|
26
|
+
/**
|
|
27
|
+
* True when the declared role extracted 0 tokens. That is the idiom's
|
|
28
|
+
* "matched nothing", as every other plane defines it on its primary selector.
|
|
29
|
+
* A role error takes precedence: see {@link error}.
|
|
30
|
+
*/
|
|
31
|
+
readonly empty: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Roles that examined nothing, each labelled with its cause. The causes are
|
|
34
|
+
* `declared (0 tokens)`, `provided (0 files)` and `consumed (could not run: …)`.
|
|
35
|
+
*
|
|
36
|
+
* A provided or consumed role that scanned files but extracted no token is
|
|
37
|
+
* NOT listed. Nothing provided is exactly the state the unprovided check
|
|
38
|
+
* reports as a finding, and nothing consumed is an ordinary intermediate
|
|
39
|
+
* state. A role whose globs matched no file at all examined nothing, though.
|
|
40
|
+
* Every "unprovided" verdict over a dead provided role comes from a stale
|
|
41
|
+
* input.
|
|
42
|
+
*/
|
|
43
|
+
readonly unexamined: readonly string[];
|
|
44
|
+
/** The first role that could not run, as `<role>: <error>`. */
|
|
45
|
+
readonly error?: string;
|
|
46
|
+
/** Where each role's error came from, so a caller can keep its own primary-side rule. */
|
|
47
|
+
readonly roleErrors: Readonly<Partial<Record<'declared' | 'provided' | 'consumed', string>>>;
|
|
48
|
+
/**
|
|
49
|
+
* `{ unit: 'roles', expected: 3, examined: 3 - unexamined }`. A dead role
|
|
50
|
+
* therefore settles the rule to `partial` (2) in every verb that reads it,
|
|
51
|
+
* and never to a ✓.
|
|
52
|
+
*/
|
|
53
|
+
readonly coverage: IVerdictCoverage;
|
|
54
|
+
/**
|
|
55
|
+
* Settle record B for the idiom's intended-empty role units (round 13:
|
|
56
|
+
* `settleUnitLiveness(...).acceptance`, `@shrkcrft/core`) — set by the plane
|
|
57
|
+
* that settles the role globs; absent when no role unit is marked. Every
|
|
58
|
+
* reader folds it beside {@link coverage} through core's `ruleVerdictRecords`,
|
|
59
|
+
* so an acceptance reaches `accepted` at exit 0 and is never dropped.
|
|
60
|
+
*/
|
|
61
|
+
readonly unitAcceptance?: IVerdictCoverage;
|
|
62
|
+
/**
|
|
63
|
+
* The three roles' glob units settled with their `expectEmpty` markers
|
|
64
|
+
* (round 13, lane G: `settleGlobLists` over `sourceLivenessRequest`, lists
|
|
65
|
+
* `declared.files` / `provided.files` / `consumed.files`) — what an idiom's
|
|
66
|
+
* rule emptiness is decided from (`settleRuleEmptiness`). Absent when no role
|
|
67
|
+
* marks a unit.
|
|
68
|
+
*/
|
|
69
|
+
readonly liveness?: ISettledUnitLiveness;
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=i-registration-roles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i-registration-roles.d.ts","sourceRoot":"","sources":["../../src/wiring/i-registration-roles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAC7E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAEtE;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,kBAAkB;IACjC,+FAA+F;IAC/F,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;IACrC,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;IACrC,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;IACrC;;;;OAIG;IACH,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,+DAA+D;IAC/D,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,yFAAyF;IACzF,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,GAAG,UAAU,GAAG,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IAC7F;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IACpC;;;;;;OAMG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,gBAAgB,CAAC;IAC3C;;;;;;OAMG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,oBAAoB,CAAC;CAC1C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { IRegistrationIdiom } from '@shrkcrft/core';
|
|
2
|
+
import type { IIdiomRoleCoverage } from './i-idiom-role-coverage.js';
|
|
3
|
+
/**
|
|
4
|
+
* Every idiom's role coverage for the registration-graph queries (round 13,
|
|
5
|
+
* P4), from THE role authority `measureRegistrationRoles` — never re-derived
|
|
6
|
+
* from the graph's token union, which is how `wiring unprovided` printed a ✓
|
|
7
|
+
* over an idiom whose declared role matched no file while `gates check` said
|
|
8
|
+
* NOT VERIFIED over the same tree. `excludeDirs` must be the scan scope the
|
|
9
|
+
* graph was built with (`planeScanExcludeDirs`).
|
|
10
|
+
*/
|
|
11
|
+
export declare function measureIdiomRoleCoverage(cwd: string, idioms: readonly IRegistrationIdiom[], excludeDirs?: readonly string[]): IIdiomRoleCoverage[];
|
|
12
|
+
//# sourceMappingURL=measure-idiom-role-coverage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"measure-idiom-role-coverage.d.ts","sourceRoot":"","sources":["../../src/wiring/measure-idiom-role-coverage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAGrE;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,SAAS,kBAAkB,EAAE,EACrC,WAAW,GAAE,SAAS,MAAM,EAAO,GAClC,kBAAkB,EAAE,CAUtB"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { measureRegistrationRoles } from "./measure-registration-roles.js";
|
|
2
|
+
/**
|
|
3
|
+
* Every idiom's role coverage for the registration-graph queries (round 13,
|
|
4
|
+
* P4), from THE role authority `measureRegistrationRoles` — never re-derived
|
|
5
|
+
* from the graph's token union, which is how `wiring unprovided` printed a ✓
|
|
6
|
+
* over an idiom whose declared role matched no file while `gates check` said
|
|
7
|
+
* NOT VERIFIED over the same tree. `excludeDirs` must be the scan scope the
|
|
8
|
+
* graph was built with (`planeScanExcludeDirs`).
|
|
9
|
+
*/
|
|
10
|
+
export function measureIdiomRoleCoverage(cwd, idioms, excludeDirs = []) {
|
|
11
|
+
return idioms.map((idiom) => {
|
|
12
|
+
const roles = measureRegistrationRoles(cwd, idiom, excludeDirs);
|
|
13
|
+
return {
|
|
14
|
+
idiom: idiom.name,
|
|
15
|
+
coverage: roles.coverage,
|
|
16
|
+
...(roles.unitAcceptance ? { unitAcceptance: roles.unitAcceptance } : {}),
|
|
17
|
+
readGap: [roles.declared, roles.provided, roles.consumed].some((r) => r.unread.length > 0),
|
|
18
|
+
};
|
|
19
|
+
});
|
|
20
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type IRegistrationIdiom } from '@shrkcrft/core';
|
|
2
|
+
import type { IRegistrationRoles } from './i-registration-roles.js';
|
|
3
|
+
/**
|
|
4
|
+
* Measure every role of one registration idiom with `inspectSource`, the
|
|
5
|
+
* primitive every plane's coverage adapter uses.
|
|
6
|
+
*
|
|
7
|
+
* This is the ONE authority for "is this idiom empty?" and "which role examined
|
|
8
|
+
* nothing?". `gates check` (`runRegistrationPlane`), `gates coverage`
|
|
9
|
+
* (`matchRegistration`) and — round 13 (P4) — the registration-graph queries
|
|
10
|
+
* (`wiring unprovided | orphans`, finish's unprovided sub-gate, MCP
|
|
11
|
+
* `get_wiring_graph`, through `measureIdiomRoleCoverage`) all call it, so they
|
|
12
|
+
* cannot drift apart on either question. That is how a `failOnEmpty` idiom used
|
|
13
|
+
* to FAIL in one verb and pass with a ✓ in the other — and how `wiring
|
|
14
|
+
* unprovided` printed a ✓ over a declared role that matched no file. (It moved
|
|
15
|
+
* here from the CLI's gates, which re-export it: the MCP server cannot import
|
|
16
|
+
* the CLI.)
|
|
17
|
+
*
|
|
18
|
+
* A role whose globs matched a file the reader did not read (over the read
|
|
19
|
+
* cap) is neither "0 files" nor "0 tokens": it matched something it could not
|
|
20
|
+
* examine. The idiom's coverage is then the file record (`readScopeCoverage`,
|
|
21
|
+
* the one fold every plane uses), and the idiom is never `empty`, so a
|
|
22
|
+
* failOnEmpty idiom settles PARTIAL (2), not FAILED (1).
|
|
23
|
+
*/
|
|
24
|
+
export declare function measureRegistrationRoles(cwd: string, idiom: IRegistrationIdiom, excludeDirs?: readonly string[]): IRegistrationRoles;
|
|
25
|
+
//# sourceMappingURL=measure-registration-roles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"measure-registration-roles.d.ts","sourceRoot":"","sources":["../../src/wiring/measure-registration-roles.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,kBAAkB,EAGxB,MAAM,gBAAgB,CAAC;AAOxB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAEpE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,kBAAkB,EACzB,WAAW,GAAE,SAAS,MAAM,EAAO,GAClC,kBAAkB,CAuFpB"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { resolveSourceGlobs, UnitLivenessState, } from '@shrkcrft/core';
|
|
2
|
+
import { inspectSource } from "../extract/inspect-source.js";
|
|
3
|
+
import { sourceLivenessRequest } from "../extract/source-liveness-request.js";
|
|
4
|
+
import { settleGlobLists } from "../util/settle-glob-lists.js";
|
|
5
|
+
import { readScopeCoverage, readScopeOfLists } from "../util/read-scope-coverage.js";
|
|
6
|
+
import { readMatchingFiles } from "../util/walk-files.js";
|
|
7
|
+
/**
|
|
8
|
+
* Measure every role of one registration idiom with `inspectSource`, the
|
|
9
|
+
* primitive every plane's coverage adapter uses.
|
|
10
|
+
*
|
|
11
|
+
* This is the ONE authority for "is this idiom empty?" and "which role examined
|
|
12
|
+
* nothing?". `gates check` (`runRegistrationPlane`), `gates coverage`
|
|
13
|
+
* (`matchRegistration`) and — round 13 (P4) — the registration-graph queries
|
|
14
|
+
* (`wiring unprovided | orphans`, finish's unprovided sub-gate, MCP
|
|
15
|
+
* `get_wiring_graph`, through `measureIdiomRoleCoverage`) all call it, so they
|
|
16
|
+
* cannot drift apart on either question. That is how a `failOnEmpty` idiom used
|
|
17
|
+
* to FAIL in one verb and pass with a ✓ in the other — and how `wiring
|
|
18
|
+
* unprovided` printed a ✓ over a declared role that matched no file. (It moved
|
|
19
|
+
* here from the CLI's gates, which re-export it: the MCP server cannot import
|
|
20
|
+
* the CLI.)
|
|
21
|
+
*
|
|
22
|
+
* A role whose globs matched a file the reader did not read (over the read
|
|
23
|
+
* cap) is neither "0 files" nor "0 tokens": it matched something it could not
|
|
24
|
+
* examine. The idiom's coverage is then the file record (`readScopeCoverage`,
|
|
25
|
+
* the one fold every plane uses), and the idiom is never `empty`, so a
|
|
26
|
+
* failOnEmpty idiom settles PARTIAL (2), not FAILED (1).
|
|
27
|
+
*/
|
|
28
|
+
export function measureRegistrationRoles(cwd, idiom, excludeDirs = []) {
|
|
29
|
+
const declared = inspectSource(cwd, idiom.declared, excludeDirs);
|
|
30
|
+
const provided = inspectSource(cwd, idiom.provided, excludeDirs);
|
|
31
|
+
const consumed = inspectSource(cwd, idiom.consumed, excludeDirs);
|
|
32
|
+
const roles = [
|
|
33
|
+
['declared', declared],
|
|
34
|
+
['provided', provided],
|
|
35
|
+
['consumed', consumed],
|
|
36
|
+
];
|
|
37
|
+
// Round 13 (lane G): the roles' globs settled with their `expectEmpty`
|
|
38
|
+
// markers — THE per-source request `gates coverage` builds too
|
|
39
|
+
// (`sourceLivenessRequest`, labels `declared` / `provided` / `consumed`). Only
|
|
40
|
+
// an idiom that marks a unit pays for it: without a marker there is nothing
|
|
41
|
+
// intended-empty and nothing to accept.
|
|
42
|
+
const marked = [idiom.declared, idiom.provided, idiom.consumed].some((s) => (s.expectEmptyUnits?.length ?? 0) > 0);
|
|
43
|
+
const liveness = marked
|
|
44
|
+
? settleGlobLists(sourceLivenessRequest(cwd, [
|
|
45
|
+
{ label: 'declared', source: idiom.declared },
|
|
46
|
+
{ label: 'provided', source: idiom.provided },
|
|
47
|
+
{ label: 'consumed', source: idiom.consumed },
|
|
48
|
+
], excludeDirs, idiom.name))
|
|
49
|
+
: undefined;
|
|
50
|
+
const unexamined = [];
|
|
51
|
+
// A role whose globs matched no file BECAUSE every inclusion glob asserts its
|
|
52
|
+
// target does not exist yet examined nothing on purpose: it is accepted
|
|
53
|
+
// (settle record B, `unitAcceptance`), never "PARTIAL — consumed (0 files)".
|
|
54
|
+
const accepted = [];
|
|
55
|
+
const roleErrors = {};
|
|
56
|
+
for (const [role, insp] of roles) {
|
|
57
|
+
if (insp.error !== undefined) {
|
|
58
|
+
roleErrors[role] = insp.error;
|
|
59
|
+
unexamined.push(`${role} (could not run: ${insp.error})`);
|
|
60
|
+
}
|
|
61
|
+
else if (insp.filesScanned === 0 && insp.unread.length === 0) {
|
|
62
|
+
if (liveness !== undefined && roleIntendedEmpty(liveness, role))
|
|
63
|
+
accepted.push(role);
|
|
64
|
+
else
|
|
65
|
+
unexamined.push(`${role} (0 files)`);
|
|
66
|
+
}
|
|
67
|
+
else if (role === 'declared' && insp.ids.length === 0 && insp.unread.length === 0) {
|
|
68
|
+
// The primary selector read files and extracted nothing, which is the
|
|
69
|
+
// plane's "matched nothing". Provided/consumed may legitimately be empty
|
|
70
|
+
// over live files (see IRegistrationRoles.unexamined).
|
|
71
|
+
unexamined.push(`${role} (0 tokens)`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const firstError = roles.find(([, insp]) => insp.error !== undefined);
|
|
75
|
+
// Only when some role left a file unread is the idiom's whole read scope
|
|
76
|
+
// measured, in ONE positive walk over the union of its role globs, then
|
|
77
|
+
// selected PER ROLE LIST (`readScopeOfLists`: a file two roles share is
|
|
78
|
+
// counted once, and one role's `!x` never hides another role's file). The
|
|
79
|
+
// common case pays nothing extra.
|
|
80
|
+
const scope = roles.some(([, insp]) => insp.unread.length > 0)
|
|
81
|
+
? readScopeOfLists(readMatchingFiles(cwd, unionGlobs(idiom), new Set(excludeDirs)), [idiom.declared, idiom.provided, idiom.consumed].map((role) => resolveSourceGlobs(role)))
|
|
82
|
+
: undefined;
|
|
83
|
+
// The roles JUDGED are the ones not accepted as intended-empty; an accepted
|
|
84
|
+
// role rides on the acceptance (record B), never as an examined unit.
|
|
85
|
+
const judged = roles.length - accepted.length;
|
|
86
|
+
const roleCoverage = {
|
|
87
|
+
unit: 'roles',
|
|
88
|
+
expected: judged,
|
|
89
|
+
examined: judged - unexamined.length,
|
|
90
|
+
...(unexamined.length > 0
|
|
91
|
+
? { unexamined, reason: 'matched nothing or could not run, so the role selector is probably stale' }
|
|
92
|
+
: {}),
|
|
93
|
+
};
|
|
94
|
+
// Every role intended-empty: the acceptance IS the idiom's coverage — an
|
|
95
|
+
// unsuppressed `{ expected: 0 }` would settle 2 over an accepted idiom.
|
|
96
|
+
const primary = judged === 0 && liveness?.acceptance !== undefined ? liveness.acceptance : roleCoverage;
|
|
97
|
+
return {
|
|
98
|
+
declared,
|
|
99
|
+
provided,
|
|
100
|
+
consumed,
|
|
101
|
+
empty: declared.ids.length === 0 && declared.unread.length === 0,
|
|
102
|
+
unexamined,
|
|
103
|
+
...(firstError ? { error: `${firstError[0]}: ${firstError[1].error}` } : {}),
|
|
104
|
+
roleErrors,
|
|
105
|
+
coverage: readScopeCoverage(primary, scope),
|
|
106
|
+
...(liveness?.acceptance !== undefined ? { unitAcceptance: liveness.acceptance } : {}),
|
|
107
|
+
...(liveness !== undefined ? { liveness } : {}),
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
/** Whether every inclusion glob of a role's `files` is intended-empty (and the role has one). */
|
|
111
|
+
function roleIntendedEmpty(liveness, role) {
|
|
112
|
+
const inclusion = liveness.units.filter((u) => u.list === `${role}.files` && !u.unit.startsWith('!'));
|
|
113
|
+
return inclusion.length > 0 && inclusion.every((u) => u.state === UnitLivenessState.IntendedEmpty);
|
|
114
|
+
}
|
|
115
|
+
/** Every glob any role of the idiom walks, deduped. */
|
|
116
|
+
function unionGlobs(idiom) {
|
|
117
|
+
return [
|
|
118
|
+
...new Set([
|
|
119
|
+
...resolveSourceGlobs(idiom.declared),
|
|
120
|
+
...resolveSourceGlobs(idiom.provided),
|
|
121
|
+
...resolveSourceGlobs(idiom.consumed),
|
|
122
|
+
]),
|
|
123
|
+
];
|
|
124
|
+
}
|
|
@@ -12,7 +12,14 @@ export type WiringFixRefusal =
|
|
|
12
12
|
/** The array literal could not be located in the sink file. */
|
|
13
13
|
| 'array-not-found'
|
|
14
14
|
/** The token is a quoted string in the sink; the declared side is a symbol (or vice versa). */
|
|
15
|
-
| 'token-shape-mismatch'
|
|
15
|
+
| 'token-shape-mismatch'
|
|
16
|
+
/**
|
|
17
|
+
* The sink IMPORTS its array members, so appending to the array alone would
|
|
18
|
+
* leave an unbound reference — a green gate over a file that does not
|
|
19
|
+
* compile. Raised whenever the needed import cannot be derived with
|
|
20
|
+
* certainty.
|
|
21
|
+
*/
|
|
22
|
+
| 'needs-import';
|
|
16
23
|
/** One planned edit: append `token` into the anchor array of `file`. */
|
|
17
24
|
export interface IWiringFixEdit {
|
|
18
25
|
readonly ruleId: string;
|
|
@@ -25,6 +32,14 @@ export interface IWiringFixEdit {
|
|
|
25
32
|
readonly insert: string;
|
|
26
33
|
/** The full new file contents, ready to write. */
|
|
27
34
|
readonly nextContent: string;
|
|
35
|
+
/**
|
|
36
|
+
* The import statement added alongside the array append, when the sink
|
|
37
|
+
* imports its members and the specifier was derivable. Absent when the token
|
|
38
|
+
* was already bound in the sink file.
|
|
39
|
+
*/
|
|
40
|
+
readonly importInsert?: string;
|
|
41
|
+
/** 1-based line the import statement lands on. */
|
|
42
|
+
readonly importLine?: number;
|
|
28
43
|
}
|
|
29
44
|
/** A violation the planner deliberately did not touch. */
|
|
30
45
|
export interface IWiringFixSkip {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan-wiring-fix.d.ts","sourceRoot":"","sources":["../../src/wiring/plan-wiring-fix.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAiB,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"plan-wiring-fix.d.ts","sourceRoot":"","sources":["../../src/wiring/plan-wiring-fix.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAiB,MAAM,gBAAgB,CAAC;AAIjE,OAAO,EAAqB,KAAK,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAWhF,eAAO,MAAM,iBAAiB,EAAG,0BAAmC,CAAC;AAErE,uDAAuD;AACvD,MAAM,MAAM,gBAAgB;AAC1B,mEAAmE;AACjE,gBAAgB;AAClB,iEAAiE;GAC/D,mBAAmB;AACrB,wDAAwD;GACtD,qBAAqB;AACvB,+DAA+D;GAC7D,iBAAiB;AACnB,+FAA+F;GAC7F,sBAAsB;AACxB;;;;;GAKG;GACD,cAAc,CAAC;AAEnB,wEAAwE;AACxE,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,oDAAoD;IACpD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,uFAAuF;IACvF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,yEAAyE;IACzE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,kDAAkD;IAClD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,kDAAkD;IAClD,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,0DAA0D;AAC1D,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,OAAO,iBAAiB,CAAC;IAC1C,QAAQ,CAAC,KAAK,EAAE,SAAS,cAAc,EAAE,CAAC;IAC1C,QAAQ,CAAC,OAAO,EAAE,SAAS,cAAc,EAAE,CAAC;CAC7C;AAED,2CAA2C;AAC3C,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAuKD;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,WAAW,EACjB,UAAU,EAAE,SAAS,gBAAgB,EAAE,EACvC,KAAK,EAAE,SAAS,cAAc,EAAE,GAC/B,cAAc,CA2KhB"}
|