@ecoma-io/archkeep 0.26.0 → 0.27.1
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 +4 -3
- package/package.json +2 -1
- package/src/architecture-intent/model.mjs +2 -2
- package/src/commands/README.md +7 -4
- package/src/commands/analyze-capability.mjs +2 -2
- package/src/commands/change-intent.mjs +2 -2
- package/src/commands/change.mjs +9 -5
- package/src/commands/check-capability.mjs +2 -2
- package/src/commands/check.mjs +3 -5
- package/src/commands/compare-capability.mjs +2 -2
- package/src/commands/completeness.mjs +2 -2
- package/src/commands/delta-snapshot.mjs +17 -0
- package/src/commands/delta.mjs +9 -5
- package/src/commands/diff.mjs +2 -2
- package/src/commands/evolution.mjs +10 -0
- package/src/commands/explain-capability.mjs +2 -2
- package/src/commands/fitness.mjs +2 -2
- package/src/commands/govern-capability.mjs +2 -2
- package/src/commands/inspect-capability.mjs +2 -2
- package/src/commands/rules-capability.mjs +2 -2
- package/src/commands/scenario-evaluation.mjs +97 -3
- package/src/corpus/goldens/adr.json +2 -2
- package/src/corpus/goldens/change.json +6 -5
- package/src/corpus/goldens/change.text +2 -2
- package/src/corpus/goldens/check.json +2 -2
- package/src/corpus/goldens/context.json +2 -2
- package/src/corpus/goldens/debt.json +4 -4
- package/src/corpus/goldens/debt.text +2 -2
- package/src/corpus/goldens/decisions.json +2 -2
- package/src/corpus/goldens/delta.json +4 -4
- package/src/corpus/goldens/delta.text +1 -1
- package/src/corpus/goldens/diff.json +4 -4
- package/src/corpus/goldens/diff.text +1 -1
- package/src/corpus/goldens/discover.json +2 -2
- package/src/corpus/goldens/drift.json +2 -2
- package/src/corpus/goldens/evolution.json +4 -2
- package/src/corpus/goldens/explain.json +2 -2
- package/src/corpus/goldens/fitness.json +2 -2
- package/src/corpus/goldens/graph.json +2 -2
- package/src/corpus/goldens/health.json +2 -2
- package/src/corpus/goldens/history.json +3 -3
- package/src/corpus/goldens/history.text +1 -1
- package/src/corpus/goldens/impact.json +2 -2
- package/src/corpus/goldens/provenance.json +2 -2
- package/src/corpus/goldens/reconcile.json +2 -2
- package/src/corpus/goldens/report.json +2 -2
- package/src/corpus/goldens/report.text +1 -1
- package/src/corpus/goldens/scenario.json +2 -2
- package/src/corpus/goldens/trajectory.json +3 -3
- package/src/corpus/goldens/trajectory.text +1 -1
- package/src/corpus/goldens/waivers.json +2 -2
- package/src/go-work.mjs +4 -5
- package/src/governance/debt-ledger.mjs +5 -2
- package/src/governance/evolution-event.mjs +1 -2
- package/src/governance/reconcile-score.mjs +59 -9
- package/src/intent/intent-manifest.json +8 -8
- package/src/providers/nx-static.mjs +4 -4
- package/src/report/text.mjs +1 -1
- package/src/rules/edge-constraints.mjs +4 -5
- package/src/rules/index.mjs +8 -10
- package/src/tsconfig-paths.mjs +4 -5
- package/src/fixtures/evolution-lifecycle/workspace.mjs +0 -248
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"tool": {
|
|
4
4
|
"name": "@ecoma-io/archkeep",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.27.1"
|
|
6
6
|
},
|
|
7
7
|
"command": "debt",
|
|
8
8
|
"workspace": {
|
|
9
|
-
"root": "
|
|
9
|
+
"root": "<fixture-root>",
|
|
10
10
|
"provider": "native",
|
|
11
11
|
"marker": "archkeep.json",
|
|
12
12
|
"provenance": {
|
|
@@ -31,10 +31,10 @@
|
|
|
31
31
|
]
|
|
32
32
|
},
|
|
33
33
|
"result": {
|
|
34
|
-
"dir": "
|
|
34
|
+
"dir": "<fixture-root>/.archkeep-history",
|
|
35
35
|
"snapshots": 1,
|
|
36
36
|
"agings": false,
|
|
37
|
-
"sampleTime": "2026-09-
|
|
37
|
+
"sampleTime": "2026-09-08T10:33:14.692Z",
|
|
38
38
|
"entries": [],
|
|
39
39
|
"resolved": [],
|
|
40
40
|
"total": 0,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
debt
|
|
1
|
+
debt <fixture-root>/.archkeep-history
|
|
2
2
|
0 entries across 1 snapshot — ages not yet established (fewer than two snapshots)
|
|
3
3
|
✔ no architecture debt — no waivers, aspirational gaps, drift or unresolved intent
|
|
4
4
|
no event store linked — lifecycle refs unavailable
|
|
5
5
|
total 0 entries · byKind: waiver 0, expired-waiver 0, aspirational-gap 0, drift 0, unresolved 0 · bySeverity: high 0, medium 0, low 0
|
|
6
|
-
sampled 2026-09-
|
|
6
|
+
sampled 2026-09-08T10:33:14.369Z
|
|
7
7
|
✔ complete (2 imports in 3 files across 3 projects)
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"tool": {
|
|
4
4
|
"name": "@ecoma-io/archkeep",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.27.1"
|
|
6
6
|
},
|
|
7
7
|
"command": "decisions",
|
|
8
8
|
"workspace": {
|
|
9
|
-
"root": "
|
|
9
|
+
"root": "<fixture-root>",
|
|
10
10
|
"provider": "native",
|
|
11
11
|
"marker": "docs/adr",
|
|
12
12
|
"provenance": null
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"tool": {
|
|
4
4
|
"name": "@ecoma-io/archkeep",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.27.1"
|
|
6
6
|
},
|
|
7
7
|
"command": "delta",
|
|
8
8
|
"workspace": {
|
|
9
|
-
"root": "
|
|
9
|
+
"root": "<fixture-root>",
|
|
10
10
|
"provider": "native",
|
|
11
11
|
"marker": "archkeep.json",
|
|
12
12
|
"provenance": {
|
|
@@ -28,10 +28,10 @@
|
|
|
28
28
|
},
|
|
29
29
|
"result": {
|
|
30
30
|
"baseline": {
|
|
31
|
-
"path": "
|
|
31
|
+
"path": "<fixture-root>/.archkeep-delta.json",
|
|
32
32
|
"tool": {
|
|
33
33
|
"name": "@ecoma-io/archkeep",
|
|
34
|
-
"version": "0.
|
|
34
|
+
"version": "0.27.1"
|
|
35
35
|
},
|
|
36
36
|
"provider": "native",
|
|
37
37
|
"provenance": {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
baseline
|
|
1
|
+
baseline <fixture-root>/.archkeep-delta.json — 1fd51709, 2 records, 3 projects
|
|
2
2
|
head 1fd51709, 2 records, 3 projects
|
|
3
3
|
✔ no introduced violations — compared baseline 1fd51709 (2 records) against head 1fd51709 (2 records, 3 analyzed files, 3 projects)
|
|
4
4
|
classifications none
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"tool": {
|
|
4
4
|
"name": "@ecoma-io/archkeep",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.27.1"
|
|
6
6
|
},
|
|
7
7
|
"command": "diff",
|
|
8
8
|
"workspace": {
|
|
9
|
-
"root": "
|
|
9
|
+
"root": "<fixture-root>",
|
|
10
10
|
"provider": "native",
|
|
11
11
|
"marker": "archkeep.json",
|
|
12
12
|
"provenance": {
|
|
@@ -30,10 +30,10 @@
|
|
|
30
30
|
},
|
|
31
31
|
"result": {
|
|
32
32
|
"baseline": {
|
|
33
|
-
"path": "
|
|
33
|
+
"path": "<fixture-root>/.archkeep-graph.json",
|
|
34
34
|
"projects": 3,
|
|
35
35
|
"edges": 2,
|
|
36
|
-
"toolVersion": "0.
|
|
36
|
+
"toolVersion": "0.27.1",
|
|
37
37
|
"provenance": {
|
|
38
38
|
"commit": "1fd51709c377d99a6139891e1200291cf08aede9",
|
|
39
39
|
"remote": null,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
baseline
|
|
1
|
+
baseline <fixture-root>/.archkeep-graph.json — 3 projects, 2 edges
|
|
2
2
|
head 3 projects, 2 edges
|
|
3
3
|
✔ no boundary-rule impact
|
|
4
4
|
✔ no changes between baseline and head (2 imports in 3 files across 3 projects; per-edge rule-impact covers only depConstraints (3 of 15 violation types; standing edges adjacent to a tags-changed project are re-judged under both sides' tags). A dependency with no rule-impact may still violate npm-ban, circular-dependency, lazy-load, or other rules that require import-site details. Run check for the complete verdict.)
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"tool": {
|
|
4
4
|
"name": "@ecoma-io/archkeep",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.27.1"
|
|
6
6
|
},
|
|
7
7
|
"command": "discover",
|
|
8
8
|
"workspace": {
|
|
9
|
-
"root": "
|
|
9
|
+
"root": "<fixture-root>",
|
|
10
10
|
"provider": "native",
|
|
11
11
|
"marker": "archkeep.json",
|
|
12
12
|
"provenance": {
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"tool": {
|
|
4
4
|
"name": "@ecoma-io/archkeep",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.27.1"
|
|
6
6
|
},
|
|
7
7
|
"command": "drift",
|
|
8
8
|
"workspace": {
|
|
9
|
-
"root": "
|
|
9
|
+
"root": "<fixture-root>",
|
|
10
10
|
"provider": "native",
|
|
11
11
|
"marker": "archkeep.json",
|
|
12
12
|
"provenance": {
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"tool": {
|
|
4
4
|
"name": "@ecoma-io/archkeep",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.27.1"
|
|
6
6
|
},
|
|
7
7
|
"command": "evolution",
|
|
8
8
|
"workspace": {
|
|
9
|
-
"root": "
|
|
9
|
+
"root": "<fixture-root>",
|
|
10
10
|
"provider": "native",
|
|
11
11
|
"marker": "archkeep.json",
|
|
12
12
|
"provenance": {
|
|
@@ -228,6 +228,7 @@
|
|
|
228
228
|
"unknown": []
|
|
229
229
|
},
|
|
230
230
|
"debt": {
|
|
231
|
+
"judged": true,
|
|
231
232
|
"introduced": [],
|
|
232
233
|
"resolved": []
|
|
233
234
|
},
|
|
@@ -309,6 +310,7 @@
|
|
|
309
310
|
"unknown": []
|
|
310
311
|
},
|
|
311
312
|
"debt": {
|
|
313
|
+
"judged": true,
|
|
312
314
|
"introduced": [],
|
|
313
315
|
"resolved": []
|
|
314
316
|
},
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"tool": {
|
|
4
4
|
"name": "@ecoma-io/archkeep",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.27.1"
|
|
6
6
|
},
|
|
7
7
|
"command": "explain",
|
|
8
8
|
"workspace": {
|
|
9
|
-
"root": "
|
|
9
|
+
"root": "<fixture-root>",
|
|
10
10
|
"provider": "native",
|
|
11
11
|
"marker": "archkeep.json",
|
|
12
12
|
"provenance": {
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"tool": {
|
|
4
4
|
"name": "@ecoma-io/archkeep",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.27.1"
|
|
6
6
|
},
|
|
7
7
|
"command": "fitness",
|
|
8
8
|
"workspace": {
|
|
9
|
-
"root": "
|
|
9
|
+
"root": "<fixture-root>",
|
|
10
10
|
"provider": "native",
|
|
11
11
|
"marker": "archkeep.json",
|
|
12
12
|
"provenance": {
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"tool": {
|
|
4
4
|
"name": "@ecoma-io/archkeep",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.27.1"
|
|
6
6
|
},
|
|
7
7
|
"command": "graph",
|
|
8
8
|
"workspace": {
|
|
9
|
-
"root": "
|
|
9
|
+
"root": "<fixture-root>",
|
|
10
10
|
"provider": "native",
|
|
11
11
|
"marker": "archkeep.json",
|
|
12
12
|
"provenance": {
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"tool": {
|
|
4
4
|
"name": "@ecoma-io/archkeep",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.27.1"
|
|
6
6
|
},
|
|
7
7
|
"command": "health",
|
|
8
8
|
"workspace": {
|
|
9
|
-
"root": "
|
|
9
|
+
"root": "<fixture-root>",
|
|
10
10
|
"provider": "native",
|
|
11
11
|
"marker": "archkeep.json",
|
|
12
12
|
"provenance": {
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"tool": {
|
|
4
4
|
"name": "@ecoma-io/archkeep",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.27.1"
|
|
6
6
|
},
|
|
7
7
|
"command": "history",
|
|
8
8
|
"workspace": {
|
|
9
|
-
"root": "
|
|
9
|
+
"root": "<fixture-root>",
|
|
10
10
|
"provider": "native",
|
|
11
11
|
"marker": "archkeep.json",
|
|
12
12
|
"provenance": {
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
]
|
|
30
30
|
},
|
|
31
31
|
"result": {
|
|
32
|
-
"dir": "
|
|
32
|
+
"dir": "<fixture-root>/.archkeep-history",
|
|
33
33
|
"captured": null,
|
|
34
34
|
"snapshots": [
|
|
35
35
|
{
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
history
|
|
1
|
+
history <fixture-root>/.archkeep-history
|
|
2
2
|
1 snapshot, 0 transitions (2 imports in 3 files across 3 projects)
|
|
3
3
|
0 0001-71341a04.json 71341a04
|
|
4
4
|
✔ one snapshot, no transitions yet — capture again after an architectural change
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"tool": {
|
|
4
4
|
"name": "@ecoma-io/archkeep",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.27.1"
|
|
6
6
|
},
|
|
7
7
|
"command": "impact",
|
|
8
8
|
"workspace": {
|
|
9
|
-
"root": "
|
|
9
|
+
"root": "<fixture-root>",
|
|
10
10
|
"provider": "native",
|
|
11
11
|
"marker": "archkeep.json",
|
|
12
12
|
"provenance": {
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"tool": {
|
|
4
4
|
"name": "@ecoma-io/archkeep",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.27.1"
|
|
6
6
|
},
|
|
7
7
|
"command": "provenance",
|
|
8
8
|
"workspace": {
|
|
9
|
-
"root": "
|
|
9
|
+
"root": "<fixture-root>",
|
|
10
10
|
"provider": "native",
|
|
11
11
|
"marker": "archkeep.json",
|
|
12
12
|
"provenance": {
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"tool": {
|
|
4
4
|
"name": "@ecoma-io/archkeep",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.27.1"
|
|
6
6
|
},
|
|
7
7
|
"command": "reconcile",
|
|
8
8
|
"workspace": {
|
|
9
|
-
"root": "
|
|
9
|
+
"root": "<fixture-root>",
|
|
10
10
|
"provider": "native",
|
|
11
11
|
"marker": "archkeep.json",
|
|
12
12
|
"provenance": {
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"tool": {
|
|
4
4
|
"name": "@ecoma-io/archkeep",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.27.1"
|
|
6
6
|
},
|
|
7
7
|
"command": "report",
|
|
8
8
|
"workspace": {
|
|
9
|
-
"root": "
|
|
9
|
+
"root": "<fixture-root>",
|
|
10
10
|
"provider": "native",
|
|
11
11
|
"marker": "archkeep.json",
|
|
12
12
|
"provenance": {
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"tool": {
|
|
4
4
|
"name": "@ecoma-io/archkeep",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.27.1"
|
|
6
6
|
},
|
|
7
7
|
"command": "scenario",
|
|
8
8
|
"workspace": {
|
|
9
|
-
"root": "
|
|
9
|
+
"root": "<fixture-root>",
|
|
10
10
|
"provider": "native",
|
|
11
11
|
"marker": "archkeep.json",
|
|
12
12
|
"provenance": {
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"tool": {
|
|
4
4
|
"name": "@ecoma-io/archkeep",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.27.1"
|
|
6
6
|
},
|
|
7
7
|
"command": "trajectory",
|
|
8
8
|
"workspace": {
|
|
9
|
-
"root": "
|
|
9
|
+
"root": "<fixture-root>",
|
|
10
10
|
"provider": "native",
|
|
11
11
|
"marker": "archkeep.json",
|
|
12
12
|
"provenance": {
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
]
|
|
31
31
|
},
|
|
32
32
|
"result": {
|
|
33
|
-
"dir": "
|
|
33
|
+
"dir": "<fixture-root>/.archkeep-history",
|
|
34
34
|
"observations": {
|
|
35
35
|
"count": 1,
|
|
36
36
|
"basis": "graph_snapshots",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
trajectory
|
|
1
|
+
trajectory <fixture-root>/.archkeep-history
|
|
2
2
|
1 observation (graph_snapshots), 0 transitions
|
|
3
3
|
✖ insufficient_history: a trajectory needs at least two observations — derived values are unavailable, not zero
|
|
4
4
|
signals architecture 0 · policy 0 · provider 0 · code drift 0 · incomparable 0 · unchanged 0
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"tool": {
|
|
4
4
|
"name": "@ecoma-io/archkeep",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.27.1"
|
|
6
6
|
},
|
|
7
7
|
"command": "waivers",
|
|
8
8
|
"workspace": {
|
|
9
|
-
"root": "
|
|
9
|
+
"root": "<fixture-root>",
|
|
10
10
|
"provider": "native",
|
|
11
11
|
"marker": "archkeep.json",
|
|
12
12
|
"provenance": {
|
package/src/go-work.mjs
CHANGED
|
@@ -276,13 +276,12 @@ function useDirectory(usePath, workspaceRoot) {
|
|
|
276
276
|
* - **`goWorkOutsideUse`** — a `use` entry above the workspace root. Whatever
|
|
277
277
|
* it builds, no run over this workspace can cover it.
|
|
278
278
|
*
|
|
279
|
-
* One of the FOUR finding families
|
|
279
|
+
* One of the FOUR finding families: no
|
|
280
280
|
* Finding supertype exists, and the relationship pin lives on
|
|
281
|
-
* `./rules/index.mjs`'s `violationOf` header
|
|
281
|
+
* `./rules/index.mjs`'s `violationOf` header (stated in
|
|
282
|
+
* `../../../docs/concepts/evidence.md`'s "Four finding families"). These findings stay this
|
|
282
283
|
* family's own shape and fold into the one verdict lane as count keys into
|
|
283
|
-
* `verdictFor` (`./verdict.mjs`).
|
|
284
|
-
* "Finding — the unowned concept" section of
|
|
285
|
-
* `../../../docs/architecture/refactor/SEMANTIC-MODEL.md`.
|
|
284
|
+
* `verdictFor` (`./verdict.mjs`).
|
|
286
285
|
*
|
|
287
286
|
* @param {{ uses: { path: string, line: number, column: number }[],
|
|
288
287
|
* workspaceRoot: string,
|
|
@@ -208,7 +208,10 @@ export function driftFactOf(finding) {
|
|
|
208
208
|
*
|
|
209
209
|
* @param {object} baseVerdict A `judgeIntent` result over the base graph.
|
|
210
210
|
* @param {object} headVerdict A `judgeIntent` result over the head graph.
|
|
211
|
-
* @returns {{introduced: string[], resolved: string[]}} Stable
|
|
211
|
+
* @returns {{judged: true, introduced: string[], resolved: string[]}} Stable
|
|
212
|
+
* debt ids, marked judged — the in-band complement of `judged: false`, so a
|
|
213
|
+
* consumer can always distinguish "no debt existed" from "debt could not be
|
|
214
|
+
* judged" (see `../../AGENTS.md`'s invariant).
|
|
212
215
|
*/
|
|
213
216
|
export function debtChangeDiff(baseVerdict, headVerdict) {
|
|
214
217
|
const driftOf = (v) => (v.findings ?? []).map((f) => debtFactId("drift", driftFactOf(f)));
|
|
@@ -218,7 +221,7 @@ export function debtChangeDiff(baseVerdict, headVerdict) {
|
|
|
218
221
|
const headIds = new Set([...driftOf(headVerdict), ...gapOf(headVerdict)]);
|
|
219
222
|
const introduced = [...headIds].filter((id) => !baseIds.has(id)).sort();
|
|
220
223
|
const resolved = [...baseIds].filter((id) => !headIds.has(id)).sort();
|
|
221
|
-
return { introduced, resolved };
|
|
224
|
+
return { judged: true, introduced, resolved };
|
|
222
225
|
}
|
|
223
226
|
/**
|
|
224
227
|
* Reduces an `opts.events` value to a loaded event array, or `null` when no
|
|
@@ -198,8 +198,7 @@ export function escapeIdentityField(value) {
|
|
|
198
198
|
* index maps, `trajectory`'s persistence sets — and is never stored. Different
|
|
199
199
|
* media, one law: each family keeps exactly one identity constructor, and
|
|
200
200
|
* consumers consume a constructor's output rather than re-deriving a second
|
|
201
|
-
* spelling of it (`../../../../docs/adr/0008-snapshot-identity-per-family.md
|
|
202
|
-
* INV-6 in `../../../../docs/architecture/refactor/INVARIANTS.md`). An edge
|
|
201
|
+
* spelling of it (`../../../../docs/adr/0008-snapshot-identity-per-family.md`). An edge
|
|
203
202
|
* reaches this module only as its raw triple, never as a pre-built string
|
|
204
203
|
* from either spelling (`evolutionBoundary` below refuses one), and a
|
|
205
204
|
* `\0`-joined diff key written into an event would give one edge two
|
|
@@ -268,8 +268,13 @@ export function scoreEdge(edge, keys, intentForbiddenPairs, tagForbiddenPairs) {
|
|
|
268
268
|
* Boundary `allowed`/`forbidden` rows are scored from the canonical judge's
|
|
269
269
|
* findings (matched exactly by `from`/`to`): a `forbidden` row with an
|
|
270
270
|
* `intentForbiddenEdge` finding is `unexpected`, an `allowed` row with an
|
|
271
|
-
* `intentAllowedMissing` finding is `absent`. Project
|
|
272
|
-
*
|
|
271
|
+
* `intentAllowedMissing` finding is `absent`. Project rows are scored against
|
|
272
|
+
* the observed names, and the two forbidden drift planes are scored from the
|
|
273
|
+
* judge's findings as well — `dependencies.forbidden` through its
|
|
274
|
+
* `dependencyForbidden` findings, `forbiddenTags` through its
|
|
275
|
+
* `tagDependencyForbidden` witnesses attributed via `tagsByProject` — so a
|
|
276
|
+
* row's verdict IS the verdict `check` and `drift` render, including the
|
|
277
|
+
* transitive closure a direct-edge re-derivation would read as "match". A
|
|
273
278
|
* `dependencies.allowed` row is an allowlist entry, not an existence claim —
|
|
274
279
|
* its absence in the graph is not divergence, so it scores `match` either
|
|
275
280
|
* way (the divergent direction is the observed edge outside the list, scored
|
|
@@ -285,7 +290,29 @@ export function scoreIntentRows(intent, judgeVerdict, observed, tagsByProject) {
|
|
|
285
290
|
// used by its own test
|
|
286
291
|
const rows = [];
|
|
287
292
|
const observedNames = new Set(observed.projects.map((p) => p.name));
|
|
288
|
-
|
|
293
|
+
// The judge has already judged every forbidden plane on the any-path
|
|
294
|
+
// closure (`../architecture-intent/judge.mjs` emits `dependencyForbidden`
|
|
295
|
+
// and `tagDependencyForbidden` for direct AND transitive paths, as concrete
|
|
296
|
+
// `source`/`target` project names with `boundaryFrom: null`). These two
|
|
297
|
+
// projections score the drift rows from those findings — projecting the
|
|
298
|
+
// canonical verdict, never re-deriving reachability here: a re-walk of the
|
|
299
|
+
// direct-edge list would score a transitive violation the judge reported
|
|
300
|
+
// as a row "match", the divergence `check` and `drift` do report. The
|
|
301
|
+
// judge's pairless findings (`intentUnknownProject`, `intentUnknownTag`)
|
|
302
|
+
// carry no witness pair; the rows they belong to are scored below from the
|
|
303
|
+
// observed names and tags themselves — the same existence predicate the
|
|
304
|
+
// judge used to emit them: a row whose endpoint can never resolve is
|
|
305
|
+
// unknown/unverifiable, never a silent "match".
|
|
306
|
+
const dependencyForbiddenPairs = new Set();
|
|
307
|
+
const tagForbiddenWitnesses = [];
|
|
308
|
+
for (const finding of judgeVerdict.findings) {
|
|
309
|
+
if (finding.source === null || finding.target === null) continue;
|
|
310
|
+
if (finding.rule === "dependencyForbidden") {
|
|
311
|
+
dependencyForbiddenPairs.add(`${finding.source} → ${finding.target}`);
|
|
312
|
+
} else if (finding.rule === "tagDependencyForbidden") {
|
|
313
|
+
tagForbiddenWitnesses.push([finding.source, finding.target]);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
289
316
|
|
|
290
317
|
const boundaryFinding = new Map();
|
|
291
318
|
for (const finding of judgeVerdict.findings) {
|
|
@@ -341,22 +368,45 @@ export function scoreIntentRows(intent, judgeVerdict, observed, tagsByProject) {
|
|
|
341
368
|
}
|
|
342
369
|
for (const forbidden of dependencies.forbidden ?? []) {
|
|
343
370
|
const key = `${forbidden.source} → ${forbidden.target}`;
|
|
371
|
+
// A row naming a project the observed architecture does not have can
|
|
372
|
+
// never fire — the judge reports it as `intentUnknownProject` with no
|
|
373
|
+
// witness pair, so the projection above stays empty for it. Reading
|
|
374
|
+
// that as "match — the ban holds" would be the silent direction; score
|
|
375
|
+
// it unknown, mirroring the boundary plane (`reconcileScores`).
|
|
376
|
+
if (!observedNames.has(forbidden.source) || !observedNames.has(forbidden.target)) {
|
|
377
|
+
row("edge", key, "unknown", "intentUnknownProject", "forbidden", key);
|
|
378
|
+
continue;
|
|
379
|
+
}
|
|
380
|
+
const violated = dependencyForbiddenPairs.has(key);
|
|
344
381
|
row(
|
|
345
382
|
"edge",
|
|
346
383
|
key,
|
|
347
|
-
|
|
348
|
-
|
|
384
|
+
violated ? "unexpected" : "match",
|
|
385
|
+
violated ? "dependencyForbidden" : "match",
|
|
349
386
|
"forbidden",
|
|
350
387
|
key,
|
|
351
388
|
);
|
|
352
389
|
}
|
|
353
390
|
|
|
391
|
+
// Every tag any observed project carries — the existence side of a
|
|
392
|
+
// `forbiddenTags` row, the same vocabulary the judge checks when it emits
|
|
393
|
+
// `intentUnknownTag`.
|
|
394
|
+
const allTags = new Set();
|
|
395
|
+
for (const tags of tagsByProject.values()) {
|
|
396
|
+
for (const tag of tags) allTags.add(tag);
|
|
397
|
+
}
|
|
354
398
|
for (const tagRow of intent.forbiddenTags ?? []) {
|
|
355
399
|
const key = `${tagRow.from} → ${tagRow.to}`;
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
400
|
+
// A row naming a tag no observed project carries can never fire — the
|
|
401
|
+
// judge reports it as `intentUnknownTag` with no witness pair. Score it
|
|
402
|
+
// unknown, never a silent "match".
|
|
403
|
+
if (!allTags.has(tagRow.from) || !allTags.has(tagRow.to)) {
|
|
404
|
+
row("tag", key, "unknown", "intentUnknownTag", "tag-forbidden", key);
|
|
405
|
+
continue;
|
|
406
|
+
}
|
|
407
|
+
const violated = tagForbiddenWitnesses.some(([source, target]) => {
|
|
408
|
+
const sourceTags = tagsByProject.get(source) ?? [];
|
|
409
|
+
const targetTags = tagsByProject.get(target) ?? [];
|
|
360
410
|
return sourceTags.includes(tagRow.from) && targetTags.includes(tagRow.to);
|
|
361
411
|
});
|
|
362
412
|
row(
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"type": "source-evidence",
|
|
53
53
|
"path": "cli.mjs",
|
|
54
54
|
"assertion": "Exit codes 0/1/3 distinguish clean/findings/cannot-look",
|
|
55
|
-
"sha256": "
|
|
55
|
+
"sha256": "536fef05cdf8d6ec8a5c364819d2dcbf61cdcf75b638463e98b89d6073e27851"
|
|
56
56
|
}
|
|
57
57
|
],
|
|
58
58
|
"status": "proven"
|
|
@@ -66,13 +66,13 @@
|
|
|
66
66
|
"type": "behavioral-test",
|
|
67
67
|
"path": "src/intent/intent.test.mjs",
|
|
68
68
|
"assertion": "analysis output conforms to the frozen contract schema (no extra verdict/policy fields); analysis output is invariant under project tag changes (three workspaces differing only in project tag fields compared byte-for-byte)",
|
|
69
|
-
"sha256": "
|
|
69
|
+
"sha256": "8c481f1230ae8700469816018fba99017a0014920b12bebdf262ceb241cba745"
|
|
70
70
|
},
|
|
71
71
|
{
|
|
72
72
|
"type": "architecture-test",
|
|
73
73
|
"path": "src/intent/intent.test.mjs",
|
|
74
74
|
"assertion": "the gate walks every production analysis module and fails when judging vocabulary (judge/forbid/permit/allow/ban) appears in code",
|
|
75
|
-
"sha256": "
|
|
75
|
+
"sha256": "8c481f1230ae8700469816018fba99017a0014920b12bebdf262ceb241cba745"
|
|
76
76
|
},
|
|
77
77
|
{
|
|
78
78
|
"type": "source-evidence",
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
"type": "source-evidence",
|
|
85
85
|
"path": "AGENTS.md",
|
|
86
86
|
"assertion": "src/graph/ is a lossy view of analysis, on purpose; src/analysis/ never judges",
|
|
87
|
-
"sha256": "
|
|
87
|
+
"sha256": "6ab8eef7a1ec2a8bde81393880cc6d29b1f089b01ffec403b31846c5d3a1a830"
|
|
88
88
|
}
|
|
89
89
|
],
|
|
90
90
|
"status": "proven"
|
|
@@ -136,7 +136,7 @@
|
|
|
136
136
|
"type": "source-evidence",
|
|
137
137
|
"path": "src/commands/diff.mjs",
|
|
138
138
|
"assertion": "parseBaseline validates schemaVersion; refuses unknown versions",
|
|
139
|
-
"sha256": "
|
|
139
|
+
"sha256": "59e6e8f1cb0535cbec241f6daf99c10f5a679c798e66fcc1f4afb5329bc6497a"
|
|
140
140
|
}
|
|
141
141
|
],
|
|
142
142
|
"status": "proven"
|
|
@@ -156,7 +156,7 @@
|
|
|
156
156
|
"type": "source-evidence",
|
|
157
157
|
"path": "src/commands/diff.mjs",
|
|
158
158
|
"assertion": "computeDiff returns structural diff; policyMismatch detected via fingerprint; computeRuleImpact for depConstraints-only context",
|
|
159
|
-
"sha256": "
|
|
159
|
+
"sha256": "59e6e8f1cb0535cbec241f6daf99c10f5a679c798e66fcc1f4afb5329bc6497a"
|
|
160
160
|
}
|
|
161
161
|
],
|
|
162
162
|
"status": "proven"
|
|
@@ -236,7 +236,7 @@
|
|
|
236
236
|
"type": "behavioral-test",
|
|
237
237
|
"path": "src/intent/intent.test.mjs",
|
|
238
238
|
"assertion": "depConstraints verdicts from judgeEdge agree with evaluate in both directions (violating edge found by both, legal edge reported by neither); explain includes the same violations as evaluate at a given site",
|
|
239
|
-
"sha256": "
|
|
239
|
+
"sha256": "8c481f1230ae8700469816018fba99017a0014920b12bebdf262ceb241cba745"
|
|
240
240
|
},
|
|
241
241
|
{
|
|
242
242
|
"type": "behavioral-test",
|
|
@@ -266,7 +266,7 @@
|
|
|
266
266
|
"type": "source-evidence",
|
|
267
267
|
"path": "src/commands/diff.mjs",
|
|
268
268
|
"assertion": "coverage.notes warns when ruleImpact is computed (depConstraints only, 3 of 15)",
|
|
269
|
-
"sha256": "
|
|
269
|
+
"sha256": "59e6e8f1cb0535cbec241f6daf99c10f5a679c798e66fcc1f4afb5329bc6497a"
|
|
270
270
|
},
|
|
271
271
|
{
|
|
272
272
|
"type": "documentation",
|