@ecoma-io/archkeep 0.20.1 → 0.22.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/cli.mjs +156 -66
- package/package.json +1 -1
- package/src/analysis/contract.md +32 -5
- package/src/analysis/source-util.mjs +107 -0
- package/src/analysis/typescript.mjs +86 -5
- package/src/commands/change.mjs +59 -28
- package/src/commands/check.mjs +65 -26
- package/src/commands/completeness.mjs +708 -0
- package/src/commands/context-command.mjs +13 -5
- package/src/commands/context.mjs +31 -4
- package/src/commands/coverage-verdict.mjs +184 -0
- package/src/commands/debt.mjs +18 -15
- package/src/commands/delta-classify.mjs +13 -18
- package/src/commands/delta.mjs +95 -33
- package/src/commands/diff.mjs +31 -24
- package/src/commands/discover.mjs +30 -10
- package/src/commands/drift.mjs +21 -21
- package/src/commands/edge-constraints.mjs +47 -1
- package/src/commands/evaluation-primitives.mjs +691 -0
- package/src/commands/evolution.mjs +27 -10
- package/src/commands/explain.mjs +14 -13
- package/src/commands/fitness.mjs +20 -19
- package/src/commands/graph.mjs +14 -5
- package/src/commands/health.mjs +12 -5
- package/src/commands/history.mjs +29 -15
- package/src/commands/impact-statement.mjs +31 -409
- package/src/commands/impact.mjs +18 -18
- package/src/commands/plan-context-command.mjs +10 -5
- package/src/commands/provenance-command.mjs +33 -2
- package/src/commands/reconcile.mjs +14 -17
- package/src/commands/scenario-evaluation.mjs +363 -198
- package/src/commands/scenario.mjs +32 -21
- package/src/commands/waivers.mjs +36 -28
- package/src/governance/evolution-event.mjs +62 -9
- package/src/governance/provenance-graph.mjs +479 -0
- package/src/intent/intent-manifest.json +83 -39
- package/src/report/json.mjs +32 -5
- package/src/report/provenance-text.mjs +30 -7
- package/src/report/text.mjs +82 -12
- package/src/verdict.mjs +78 -36
- package/src/workspace.mjs +126 -2
|
@@ -43,9 +43,10 @@
|
|
|
43
43
|
* comparison (never `localeCompare`), so two runs over an unchanged tree and
|
|
44
44
|
* intent produce byte-identical text and JSON.
|
|
45
45
|
*/
|
|
46
|
-
import {
|
|
46
|
+
import { blindSpotRows } from "../analysis/source-util.mjs";
|
|
47
47
|
import { jsonEnvelope, renderJson } from "../report/json.mjs";
|
|
48
48
|
import { resolveProvenance } from "./provenance.mjs";
|
|
49
|
+
import { coverageRefusal, coverageVerdict } from "./coverage-verdict.mjs";
|
|
49
50
|
import { judgeIntent } from "../architecture-intent/judge.mjs";
|
|
50
51
|
import { computeIntentFingerprint } from "../architecture-intent/intent-fingerprint.mjs";
|
|
51
52
|
import { INTENT_FILE, loadIntent } from "../architecture-intent/model.mjs";
|
|
@@ -84,9 +85,12 @@ function intentRows(intent) {
|
|
|
84
85
|
* @param {{loadIntentOverride?: (root: string) => Promise<object>}} [io]
|
|
85
86
|
* Injectable intent loader for tests.
|
|
86
87
|
* @param {{propose?: boolean}} [options] `--propose` adds the ranked candidate list.
|
|
87
|
-
* @returns {Promise<{status: "ok", reconcile
|
|
88
|
+
* @returns {Promise<{status: "ok"|"no-verdict", reconcile?: object, coverage: object,
|
|
88
89
|
* report: {text: string, json: string}}>}
|
|
89
|
-
*
|
|
90
|
+
* `status: "no-verdict"` carries no `reconcile` payload — the verdict was
|
|
91
|
+
* withheld, and the envelope's `coverage` block is the whole answer (#608).
|
|
92
|
+
* @throws {Error} on every condition the header lists except the coverage one,
|
|
93
|
+
* which returns instead of throwing.
|
|
90
94
|
*/
|
|
91
95
|
export async function reconcileCommand(commandContext, io = {}, options = {}) {
|
|
92
96
|
const { root, provider, marker, analysis } = commandContext;
|
|
@@ -94,17 +98,12 @@ export async function reconcileCommand(commandContext, io = {}, options = {}) {
|
|
|
94
98
|
refuseIncompleteGraph(commandContext);
|
|
95
99
|
|
|
96
100
|
// A reconcile verdict cannot be established over a tree it could not fully
|
|
97
|
-
// read — the same fail-closed condition `drift` enforces
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
throw new Error(
|
|
104
|
-
`archkeep: reconcile has incomplete coverage — ${notAnalyzed.length} file` +
|
|
105
|
-
`${notAnalyzed.length === 1 ? "" : "s"} could not be analyzed, so every "absent" score ` +
|
|
106
|
-
`would be ambiguous between "gone" and "never seen". Fix the unanalyzed files and re-run.`,
|
|
107
|
-
);
|
|
101
|
+
// read — the same fail-closed condition `drift` enforces, refused through
|
|
102
|
+
// the same structured envelope `./coverage-verdict.mjs` builds (#608): the
|
|
103
|
+
// verdict is withheld in-band, where a parser and `--output` can read it.
|
|
104
|
+
const completeness = coverageVerdict(commandContext);
|
|
105
|
+
if (!completeness.complete) {
|
|
106
|
+
return coverageRefusal({ command: "reconcile", commandContext, what: "reconciling" });
|
|
108
107
|
}
|
|
109
108
|
|
|
110
109
|
const intent = await (io.loadIntentOverride ?? loadIntent)(root, {
|
|
@@ -146,9 +145,7 @@ export async function reconcileCommand(commandContext, io = {}, options = {}) {
|
|
|
146
145
|
// Reconcile reads only the graph — provider failures are the same blind
|
|
147
146
|
// spots every other command reports, and a blind spot never prevents a
|
|
148
147
|
// verdict.
|
|
149
|
-
blindSpots: analysis.failures
|
|
150
|
-
.filter((failure) => !isWholeFileFailure(failure))
|
|
151
|
-
.map(({ sourceFile, line, column, reason }) => ({ file: sourceFile, line, column, reason })),
|
|
148
|
+
blindSpots: blindSpotRows(analysis.failures),
|
|
152
149
|
// Coverage notes (e.g. an `optional: true` allowed row the team has not
|
|
153
150
|
// built yet) ride here so "optional and absent" never reads as "never
|
|
154
151
|
// checked".
|