arkgate 4.8.23 → 4.8.25
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 +153 -0
- package/README.md +7 -5
- package/bin/ark-check-runtime.mjs +41 -91
- package/bin/ark-dashboard.mjs +56 -53
- package/bin/ark-layer-match.mjs +707 -121
- package/bin/ark-mcp-runtime.mjs +448 -169
- package/bin/ark-mcp.mjs +68 -4
- package/bin/ark-shared.mjs +42 -22
- package/bin/ark.mjs +65 -97
- package/bin/lib/adapter-contract-types.mjs +5 -0
- package/bin/lib/adapter-contract.mjs +15 -0
- package/bin/lib/adoption-stance.mjs +2 -2
- package/bin/lib/adr-path.mjs +3 -3
- package/bin/lib/agent-gates.mjs +0 -61
- package/bin/lib/agent-homes.mjs +12 -21
- package/bin/lib/agent-projection-command.mjs +9 -5
- package/bin/lib/ambient-state.mjs +9 -30
- package/bin/lib/analysis-engine.mjs +15 -11
- package/bin/lib/architecture-scan.mjs +61 -15
- package/bin/lib/ark-order-doctor.mjs +4 -29
- package/bin/lib/ark-order-facts.mjs +319 -17
- package/bin/lib/ark-order-sensors.mjs +28 -101
- package/bin/lib/ark-order-types.mjs +3 -2
- package/bin/lib/ark-run-doctor.mjs +17 -28
- package/bin/lib/ark-run-facts.mjs +461 -48
- package/bin/lib/ark-run-sensors.mjs +6 -4
- package/bin/lib/arkgate-pins.mjs +91 -0
- package/bin/lib/arkrule-file-hints.mjs +2 -47
- package/bin/lib/arkrules-contract.mjs +124 -133
- package/bin/lib/arkrules-sensors.mjs +55 -252
- package/bin/lib/check-args.mjs +85 -1
- package/bin/lib/ci-and-commands.mjs +24 -78
- package/bin/lib/ci-merge-boundary.mjs +1 -1
- package/bin/lib/class-source-scan.mjs +479 -0
- package/bin/lib/clone-detection.mjs +474 -0
- package/bin/lib/codex-home.mjs +5 -3
- package/bin/lib/config-contract-slices.mjs +739 -0
- package/bin/lib/config-contract.mjs +42 -607
- package/bin/lib/config-extras.mjs +16 -22
- package/bin/lib/config-warnings.mjs +32 -0
- package/bin/lib/contract-smells.mjs +33 -15
- package/bin/lib/core-ratchet.mjs +0 -2
- package/bin/lib/dashboard-cli.mjs +62 -0
- package/bin/lib/deep-module-coach.mjs +2 -4
- package/bin/lib/deploy-path.mjs +13 -38
- package/bin/lib/design-delta.mjs +1 -1
- package/bin/lib/design-smells.mjs +2 -2
- package/bin/lib/diagnostic-catalog.mjs +23 -9
- package/bin/lib/doctor-advisories.mjs +78 -8
- package/bin/lib/doctor-green-cite.mjs +1 -1
- package/bin/lib/doctor-human.mjs +1 -1
- package/bin/lib/doctor-next-actions.mjs +19 -4
- package/bin/lib/doctor-plan.mjs +9 -13
- package/bin/lib/duplication-io.mjs +572 -0
- package/bin/lib/effective-contract-load.mjs +282 -83
- package/bin/lib/enforcement-profiles.mjs +40 -4
- package/bin/lib/entry-points-io.mjs +424 -0
- package/bin/lib/extra-merge-teeth.mjs +36 -0
- package/bin/lib/field-install.mjs +38 -14
- package/bin/lib/first-run-help.mjs +10 -5
- package/bin/lib/flat-parent-importers.mjs +139 -0
- package/bin/lib/flat-parent-pilot.mjs +40 -100
- package/bin/lib/gate-files.mjs +58 -90
- package/bin/lib/git-change-scope.mjs +109 -0
- package/bin/lib/github-enforcement.mjs +166 -29
- package/bin/lib/golden-pattern.mjs +1 -1
- package/bin/lib/hook-templates.mjs +17 -15
- package/bin/lib/host-support-matrix.mjs +3 -1
- package/bin/lib/html-report-advisories.mjs +4 -0
- package/bin/lib/html-report-depth.mjs +2 -2
- package/bin/lib/html-report.mjs +2 -2
- package/bin/lib/import-graph-projection.mjs +112 -0
- package/bin/lib/import-resolve.mjs +13 -1
- package/bin/lib/improvement-compass-doctor.mjs +1 -24
- package/bin/lib/install-migrate.mjs +50 -73
- package/bin/lib/invariant-coverage-io.mjs +4 -3
- package/bin/lib/invariant-coverage.mjs +85 -11
- package/bin/lib/invariant-probe-cli.mjs +347 -0
- package/bin/lib/invariant-probe-io.mjs +165 -0
- package/bin/lib/invariant-probe-runner.mjs +268 -0
- package/bin/lib/invariant-probe-sites.mjs +174 -0
- package/bin/lib/invariant-probe-workspace.mjs +183 -0
- package/bin/lib/invariant-probe.mjs +461 -0
- package/bin/lib/invariant-tests-path.mjs +16 -22
- package/bin/lib/literal-path-drift.mjs +4 -2
- package/bin/lib/managed-upgrade.mjs +2 -8
- package/bin/lib/mcp-adoption.mjs +13 -6
- package/bin/lib/mcp-hook-payload.mjs +403 -63
- package/bin/lib/orphan-modules-io.mjs +458 -0
- package/bin/lib/orphan-modules.mjs +251 -0
- package/bin/lib/outside-importers.mjs +197 -0
- package/bin/lib/package-manager.mjs +60 -2
- package/bin/lib/parse-health.mjs +1 -1
- package/bin/lib/passthrough-commands.mjs +83 -0
- package/bin/lib/persistence-write-hint.mjs +106 -0
- package/bin/lib/pin-dependent-gates.mjs +117 -0
- package/bin/lib/policy-delta-io.mjs +219 -14
- package/bin/lib/post-green-path.mjs +1 -1
- package/bin/lib/prepare-change.mjs +115 -7
- package/bin/lib/prepare-write.mjs +2 -2
- package/bin/lib/presets.mjs +59 -73
- package/bin/lib/product-copy.mjs +1 -6
- package/bin/lib/project-root.mjs +31 -62
- package/bin/lib/remediation.mjs +23 -4
- package/bin/lib/resolved-candidate-facts.mjs +405 -117
- package/bin/lib/rules-inventory.mjs +22 -3
- package/bin/lib/rules-under-contract.mjs +247 -9
- package/bin/lib/scan-files.mjs +36 -4
- package/bin/lib/schema-validation.mjs +130 -0
- package/bin/lib/sensor-promote-cli.mjs +2 -11
- package/bin/lib/sensor-promote-io.mjs +33 -22
- package/bin/lib/sensor-promotion.mjs +1 -1
- package/bin/lib/skill-catalog-apply.mjs +1 -1
- package/bin/lib/skill-install.mjs +42 -38
- package/bin/lib/snippet-analysis.mjs +140 -6
- package/bin/lib/source-policy.mjs +34 -0
- package/bin/lib/start-install-recovery.mjs +72 -2
- package/bin/lib/start-preview.mjs +31 -1
- package/bin/lib/states-transitions-presence.mjs +3 -3
- package/bin/lib/status-command.mjs +35 -22
- package/bin/lib/status-manifest.mjs +50 -30
- package/bin/lib/status-transition-catalog.mjs +0 -6
- package/bin/lib/suggestions.mjs +3 -3
- package/bin/lib/team-parliament-io.mjs +76 -88
- package/bin/lib/team-parliament.mjs +21 -10
- package/bin/lib/upgrade-behavior-changes.mjs +2 -2
- package/bin/lib/upgrade-command.mjs +2 -24
- package/bin/lib/upgrade-outcome.mjs +1 -1
- package/bin/lib/upstream-report.mjs +21 -10
- package/bin/lib/violations.mjs +10 -9
- package/bin/lib/weakest-link.mjs +13 -0
- package/bin/lib/write-path-capabilities.mjs +6 -4
- package/dist/chunk-A5EIY3HI.cjs +5 -0
- package/dist/chunk-AHACEKSV.js +16 -0
- package/dist/chunk-SVSQVGFJ.js +5 -0
- package/dist/chunk-UN5EH4QV.cjs +16 -0
- package/dist/{configTypes-Bbf_MFGe.d.ts → configTypes-GPvvdleM.d.cts} +30 -4
- package/dist/configTypes-GPvvdleM.d.ts +257 -0
- package/dist/eslint/index.cjs +18 -5
- package/dist/eslint/index.d.cts +368 -0
- package/dist/eslint/index.d.ts +139 -156
- package/dist/eslint/index.js +11 -5
- package/dist/index.cjs +36 -35
- package/dist/index.d.cts +5547 -0
- package/dist/index.d.ts +3283 -198
- package/dist/index.js +36 -35
- package/dist/inspectorListen-6DQVJ4DC.js +1 -0
- package/dist/inspectorListen-KGMIQ2TF.cjs +1 -0
- package/dist/nestjs/index.cjs +1 -18
- package/dist/nestjs/index.d.cts +22 -0
- package/dist/nestjs/index.d.ts +1 -3
- package/dist/nestjs/index.js +1 -18
- package/dist/order/index.cjs +1 -1
- package/dist/order/index.d.cts +155 -0
- package/dist/order/index.d.ts +15 -3
- package/dist/order/index.js +1 -1
- package/dist/runtime/index.cjs +13 -30
- package/dist/{diagnosticCatalog-35mrwAHe.d.ts → runtime/index.d.cts} +828 -276
- package/dist/runtime/index.d.ts +2741 -133
- package/dist/runtime/index.js +13 -30
- package/dist/{types-Bdj32QwA.d.ts → types-CnauMQQL.d.cts} +607 -163
- package/dist/types-CnauMQQL.d.ts +1800 -0
- package/docs/README.md +3 -1
- package/docs/agent-guide.md +217 -16
- package/docs/ai-gates.md +174 -26
- package/docs/arkorder.md +32 -15
- package/docs/brownfield-adoption.md +5 -1
- package/docs/configuration.md +230 -31
- package/docs/develop.md +2 -1
- package/docs/diagnostics.md +212 -19
- package/docs/package-surface.md +35 -9
- package/docs/product-voice.md +7 -1
- package/package.json +69 -19
- package/schemas/ark.analysis-result.schema.json +15 -0
- package/schemas/ark.config.schema.json +77 -12
- package/schemas/ark.invariant-probe.schema.json +368 -0
- package/schemas/ark.resolved-candidate-facts.schema.json +1 -1
- package/schemas/ark.status-manifest.schema.json +22 -0
- package/server.json +3 -9
- package/templates/agent-skills/README.md +1 -1
- package/templates/agent-skills/ark-adopt/SKILL.md +5 -1
- package/templates/agent-skills/ark-contract/SKILL.md +17 -0
- package/templates/agent-skills/ark-coverage/SKILL.md +2 -0
- package/templates/agent-skills/ark-explore/SKILL.md +7 -0
- package/templates/agent-skills/ark-fix/SKILL.md +20 -0
- package/templates/agent-skills/ark-order/SKILL.md +4 -2
- package/templates/agent-skills/ark-place/SKILL.md +8 -0
- package/templates/agent-skills/ark-runtime/SKILL.md +6 -1
- package/templates/arkrules/PersistenceAdapters.json +1 -1
- package/templates/arkrules/PresentationAdapters.json +1 -1
- package/templates/skills/ark-adopt.md +5 -1
- package/templates/skills/ark-contract.md +17 -0
- package/templates/skills/ark-coverage.md +2 -0
- package/templates/skills/ark-explore.md +7 -0
- package/templates/skills/ark-fix.md +20 -0
- package/templates/skills/ark-order.md +4 -2
- package/templates/skills/ark-place.md +8 -0
- package/templates/skills/ark-runtime.md +6 -1
- package/bin/lib/ark-order-error.mjs +0 -18
- package/bin/lib/ark-order-invariants.mjs +0 -346
- package/dist/types-Ik_OakcI.d.ts +0 -183
package/docs/diagnostics.md
CHANGED
|
@@ -27,7 +27,10 @@ Link form for agents: `docs/diagnostics.md#RULE_ID` (exact-case HTML anchors bel
|
|
|
27
27
|
| [`LAYER_IMPORT_VIOLATION`](#LAYER_IMPORT_VIOLATION) | layer | This import is not allowed |
|
|
28
28
|
| [`LAYER_INTENT_REFERENCE_VIOLATION`](#LAYER_INTENT_REFERENCE_VIOLATION) | layer | Intent referenced across a blocked layer edge |
|
|
29
29
|
| [`LAYER_REFERENCE_VIOLATION`](#LAYER_REFERENCE_VIOLATION) | layer | Layer reference blocked (snippet / AI gate) |
|
|
30
|
+
| [`SHARED_IMPORTS_SLICE`](#SHARED_IMPORTS_SLICE) | layer | A shared root imports a slice |
|
|
30
31
|
| [`CIRCULAR_DEPENDENCY`](#CIRCULAR_DEPENDENCY) | layer | Dependency cycle |
|
|
32
|
+
| [`CROSS_WALL_DUPLICATE`](#CROSS_WALL_DUPLICATE) | layer | Code copied across a wall |
|
|
33
|
+
| [`CROSS_LAYER_DUPLICATE`](#CROSS_LAYER_DUPLICATE) | layer | Code copied in two layers |
|
|
31
34
|
| [`FORBIDDEN_GLOBAL`](#FORBIDDEN_GLOBAL) | capability | Forbidden ambient global or dual import |
|
|
32
35
|
| [`CAPABILITY_VIOLATION`](#CAPABILITY_VIOLATION) | capability | Denied effect capability |
|
|
33
36
|
| [`RAW_EVENT_PUBLISH`](#RAW_EVENT_PUBLISH) | publish | Raw event publish |
|
|
@@ -44,10 +47,14 @@ Link form for agents: `docs/diagnostics.md#RULE_ID` (exact-case HTML anchors bel
|
|
|
44
47
|
| [`ARKRULE_INVARIANT`](#ARKRULE_INVARIANT) | arkrules | ArkRule invariant failed |
|
|
45
48
|
| [`ARKRULE_SCOPE_EMPTY`](#ARKRULE_SCOPE_EMPTY) | arkrules | ArkRule appliesTo matched zero files |
|
|
46
49
|
| [`ARKRULE_HINT_BUDGET_EXHAUSTED`](#ARKRULE_HINT_BUDGET_EXHAUSTED) | arkrules | Structural-hint budget exhausted |
|
|
50
|
+
| [`ARKRULE_FILE_UNREFERENCED`](#ARKRULE_FILE_UNREFERENCED) | arkrules | ArkRules file not referenced |
|
|
51
|
+
| [`ARKRULE_DUPLICATE_ID`](#ARKRULE_DUPLICATE_ID) | arkrules | ArkRule id declared more than once |
|
|
52
|
+
| [`ARKRULE_SCOPE_ESCAPES_SLICE`](#ARKRULE_SCOPE_ESCAPES_SLICE) | arkrules | Slice ArkRule appliesTo leaves its slice |
|
|
47
53
|
| [`INVARIANT_CATALOG_EMPTY`](#INVARIANT_CATALOG_EMPTY) | arkrules | Domain invariant catalog is empty |
|
|
48
54
|
| [`INVARIANT_UNCOVERED`](#INVARIANT_UNCOVERED) | arkrules | Invariant without coverage evidence |
|
|
49
55
|
| [`INVARIANT_COVERAGE_OUTSIDE_ROOTS`](#INVARIANT_COVERAGE_OUTSIDE_ROOTS) | arkrules | Covering test outside the declared coverage roots |
|
|
50
56
|
| [`INVARIANT_COVERAGE_ROOTS_MISSING`](#INVARIANT_COVERAGE_ROOTS_MISSING) | arkrules | Coverage roots missing while an invariant is enforced |
|
|
57
|
+
| [`INVARIANT_PROBE_SURVIVED`](#INVARIANT_PROBE_SURVIVED) | arkrules | Covering tests do not pin the invariant |
|
|
51
58
|
| [`INVARIANT_TESTS_PATH_MISSING`](#INVARIANT_TESTS_PATH_MISSING) | arkrules | Domain-invariant tests path missing under adopted |
|
|
52
59
|
| [`ARKRUN_MISSING_ROOT`](#ARKRUN_MISSING_ROOT) | arkrun | No kernel factory in composition roots |
|
|
53
60
|
| [`ARKRUN_KERNEL_IN_DOMAIN`](#ARKRUN_KERNEL_IN_DOMAIN) | arkrun | Domain-role layer imports the kernel |
|
|
@@ -62,6 +69,7 @@ Link form for agents: `docs/diagnostics.md#RULE_ID` (exact-case HTML anchors bel
|
|
|
62
69
|
| [`ARKORDER_TOO_MANY_PARAMS`](#ARKORDER_TOO_MANY_PARAMS) | arkorder | Too many slow keys |
|
|
63
70
|
| [`ARKORDER_INGEST_WRITES_XI`](#ARKORDER_INGEST_WRITES_XI) | arkorder | ingest assigned into ξ |
|
|
64
71
|
| [`ARKORDER_UNVALVED_RELEASE`](#ARKORDER_UNVALVED_RELEASE) | arkorder | Second freeze without the valve |
|
|
72
|
+
| [`ARKORDER_STALE_PROPOSAL`](#ARKORDER_STALE_PROPOSAL) | arkorder | Proposal is not bound to the current Release |
|
|
65
73
|
| [`INVALID_CHANGE_PATH`](#INVALID_CHANGE_PATH) | preflight | Unsafe change path |
|
|
66
74
|
| [`DUPLICATE_CHANGE_PATH`](#DUPLICATE_CHANGE_PATH) | preflight | Duplicate path in change set |
|
|
67
75
|
| [`DELETE_TARGET_MISSING`](#DELETE_TARGET_MISSING) | preflight | Delete target missing |
|
|
@@ -72,6 +80,7 @@ Link form for agents: `docs/diagnostics.md#RULE_ID` (exact-case HTML anchors bel
|
|
|
72
80
|
| [`CANDIDATE_CONTENT_HASH_MISMATCH`](#CANDIDATE_CONTENT_HASH_MISMATCH) | preflight | Candidate content hash mismatch |
|
|
73
81
|
| [`UNDECLARED_CANDIDATE_CHANGE`](#UNDECLARED_CANDIDATE_CHANGE) | preflight | Undeclared candidate change |
|
|
74
82
|
| [`ATOMIC_PREFLIGHT_UNAVAILABLE`](#ATOMIC_PREFLIGHT_UNAVAILABLE) | preflight | Atomic preflight unavailable |
|
|
83
|
+
| [`WRITE_GATE_UNAVAILABLE`](#WRITE_GATE_UNAVAILABLE) | preflight | Write gate could not run |
|
|
75
84
|
| [`DESIGN_SMELL_REGRESSION`](#DESIGN_SMELL_REGRESSION) | preflight | Design smell regression on base-relative ratchet |
|
|
76
85
|
| [`ANALYSIS_PARSE_INCOMPLETE`](#ANALYSIS_PARSE_INCOMPLETE) | analysis | Parse incomplete |
|
|
77
86
|
| [`LEXICAL_EVIDENCE_INCOMPLETE`](#LEXICAL_EVIDENCE_INCOMPLETE) | analysis | Lexical evidence incomplete |
|
|
@@ -79,6 +88,8 @@ Link form for agents: `docs/diagnostics.md#RULE_ID` (exact-case HTML anchors bel
|
|
|
79
88
|
| [`ANALYSIS_HOST_UNAVAILABLE`](#ANALYSIS_HOST_UNAVAILABLE) | analysis | Analysis host unavailable |
|
|
80
89
|
| [`LITERAL_PATH_DRIFT`](#LITERAL_PATH_DRIFT) | drift | Literal path moved by a rename |
|
|
81
90
|
| [`LITERAL_PATH_UNRESOLVED`](#LITERAL_PATH_UNRESOLVED) | drift | Literal path does not resolve |
|
|
91
|
+
| [`ORPHAN_MODULE`](#ORPHAN_MODULE) | drift | File nothing imports |
|
|
92
|
+
| [`UNUSED_EXPORT`](#UNUSED_EXPORT) | drift | Export nothing imports by name |
|
|
82
93
|
| [`ADAPTER_NOT_ALLOWED_FOR_PORT`](#ADAPTER_NOT_ALLOWED_FOR_PORT) | adapter | Adapter not allowed for port |
|
|
83
94
|
| [`FORBIDDEN_PATTERN`](#FORBIDDEN_PATTERN) | snippet-policy | Forbidden regex pattern |
|
|
84
95
|
| [`FORBIDDEN_SUBSTRING`](#FORBIDDEN_SUBSTRING) | snippet-policy | Forbidden substring |
|
|
@@ -102,9 +113,11 @@ Link form for agents: `docs/diagnostics.md#RULE_ID` (exact-case HTML anchors bel
|
|
|
102
113
|
| [`CONFIG_UNCLASSIFIED_FILES`](#CONFIG_UNCLASSIFIED_FILES) | config | Unclassified included files |
|
|
103
114
|
| [`CONFIG_LAYER_MISSING_OWNER`](#CONFIG_LAYER_MISSING_OWNER) | config | Layer missing owner |
|
|
104
115
|
| [`CONFIG_SLICE_IDENTITY_COLLISION`](#CONFIG_SLICE_IDENTITY_COLLISION) | config | Starred slice prefixes share one id |
|
|
105
|
-
| [`CONFIG_CHILD_SLICES_VERSION`](#CONFIG_CHILD_SLICES_VERSION) | config |
|
|
116
|
+
| [`CONFIG_CHILD_SLICES_VERSION`](#CONFIG_CHILD_SLICES_VERSION) | config | Config needs a newer arkgate than a pinned copy |
|
|
106
117
|
| [`CONFIG_CHILD_SLICE_EXTENDS`](#CONFIG_CHILD_SLICE_EXTENDS) | config | Child slice id does not extend its universe |
|
|
107
118
|
| [`CONFIG_CHILD_SLICE_CROSS_UNIVERSE`](#CONFIG_CHILD_SLICE_CROSS_UNIVERSE) | config | Child slice allowance cannot cross the universe wall |
|
|
119
|
+
| [`CONFIG_CHILD_SLICES_INERT`](#CONFIG_CHILD_SLICES_INERT) | config | childSlices on a rule that cannot run it |
|
|
120
|
+
| [`CONFIG_SLICE_LEGACY_STARS_ID`](#CONFIG_SLICE_LEGACY_STARS_ID) | config | Slice id written in the 4.8.23 stars form |
|
|
108
121
|
| [`ARK_UNKNOWN`](#ARK_UNKNOWN) | meta | Unknown diagnostic |
|
|
109
122
|
|
|
110
123
|
## Layer and dependency graph
|
|
@@ -117,8 +130,8 @@ Link form for agents: `docs/diagnostics.md#RULE_ID` (exact-case HTML anchors bel
|
|
|
117
130
|
|
|
118
131
|
- **Why:** This file imported a folder it may not reach. The write doesn’t land. The same check fails the pull request.
|
|
119
132
|
- **Fix:** Branch by import kind: constants/types/pure → adopt into DomainModel or SharedKernel (do not invent a port); kernel/events/bootstrap from Persistence → inject a port or move the map to SharedTypes (Persistence must not emit); define a port only when the target is a real use-case. Type-only edges use `import type`. Then preflight again. Do not weaken the layer rule without a hash-bound policy acknowledgement.
|
|
120
|
-
- **Slice reasons:** the ruleId stays `LAYER_IMPORT_VIOLATION`. When a rule sets `childSlices`, the finding may also carry `reasonId` `CROSS_PARENT_SLICE` (this import crosses two universe slices; the child wall cannot allow another universe) or `CROSS_SIBLING_SLICE` (this import crosses two feature slices inside one universe). `siblings` may be `"deny"`, `"advisory"`, or `{ "default", "enforce" }`. An enforced importer (`enforce` entry is that child id or a subtree path of the file) is an error. Every other sibling crossing is a warning
|
|
121
|
-
- **`CROSS_PARENT_VIA_SHARED`:** `sharedImportsSlice` is `"deny-cross-parent"`. A slice reaches another universe only through a shared root. The finding's `file` is the slice that imported the shared root and `target` is the file in the other universe. The baseline key stays `ruleId|file|fromLayer|toLayer|target` and does not include `reasonId`. A shared hop that stays inside one universe is not this finding. The direct shared-root hop stays the `SHARED_IMPORTS_SLICE` warning. `"deny"` is unchanged and does not emit this reason. Doctor slice counts stay on `CROSS_PARENT_SLICE` and `CROSS_SIBLING_SLICE`. **ark-check and CI report this path. The write hook and ESLint see one edge at a time and do not block it.** arkgate 4.8.22 and older reject `"deny-cross-parent"` at config load.
|
|
133
|
+
- **Slice reasons:** the ruleId stays `LAYER_IMPORT_VIOLATION`. When a rule sets `childSlices`, the finding may also carry `reasonId` `CROSS_PARENT_SLICE` (this import crosses two universe slices; the child wall cannot allow another universe) or `CROSS_SIBLING_SLICE` (this import crosses two feature slices inside one universe). `siblings` may be `"deny"`, `"advisory"`, or `{ "default", "enforce", "ratchet" }`. An enforced importer (`enforce` entry is that child id or a subtree path of the file) is an error. Every other sibling crossing is a warning. With a baseline in use, a new advisory crossing fails only when the baseline already records an advisory crossing of that rule and that rule's advisory count grows past the recorded count (judged per rule; a recorded key whose crossing was removed still counts), or when `ratchet` is `true`; `ratchet: false` measures only. `default: "deny"` denies every sibling crossing. A `commonFolders` name counts only directly under the universe; the same folder name inside a child belongs to the child. The rule `message` is the universe-wall text; `childSlices.message` is the text for `CROSS_SIBLING_SLICE` and universe common importing a child (absent: ArkGate's default, never the rule message). `childSlices.allowedCrossSlice` may use a whole-segment `*` and clears only a sibling crossing. It does not clear `CROSS_PARENT_SLICE` or `CROSS_PARENT_VIA_SHARED`. The universe `allowedCrossSlice` still treats `*` as a literal. `childSlices.sliceAliases` maps a source path glob onto a child slice id (the universe id plus one child segment). A `from` with no wildcard in its last segment also covers its subtree. An aliased file takes that universe id and that child id for both walls, so an import into another universe is still `CROSS_PARENT_SLICE`. A bare name, a universe id alone, a target outside every universe shape, and a wildcard in `to` are rejected at config load; config load checks only the shape, and doctor flags a target universe no file belongs to (`unknownUniverse`). A glob that overlaps a slice folder is rejected. Two aliases that can match the same file are rejected. Doctor lists each alias as an owed move — the files, the target slice, and the destination folder — and does not count those files as finished. Adding aliases is a strengthening policy delta. Removing them is weakening. Additions and removals together, including a retarget, need a judgment. The baseline key does not include `reasonId`. Without `childSlices`, `reasonId` is absent on a direct edge. The write hook, ESLint, snippet analysis, ark-check, and CI all see this per-edge decision. Adapter diagnostics carry `evidence.reasonId` (plus `evidence.universeFrom` / `universeTo`) and a `nextAction` taken from that reason's own hint (an advisory `CROSS_SIBLING_SLICE` also gets the ratchet note; a blocking one gets only the action). arkgate 4.8.22 and older reject `childSlices`. A build that still types `siblings` as a string enum rejects the object at config load (`must be one of deny, advisory`). A build that still rejects unknown `childSlices` fields rejects `allowedCrossSlice` and `sliceAliases` at config load (`unknown field`). No published release through 4.8.22 accepts `sliceAliases`. Doctor may also suggest moving a flat universe-level file that exactly one child imports (`doctor.flatParentPilot`). That suggestion is not a finding, not a `ruleId`, and not part of the baseline key. A file imported by two children, by none, or by anything outside its one importing child (universe common, a shared root, another universe, tsconfig-alias importers included) is not suggested.
|
|
134
|
+
- **`CROSS_PARENT_VIA_SHARED`:** `sharedImportsSlice` is `"deny-cross-parent"`. A slice reaches another universe only through a shared root. The finding's `file` is the slice that imported the shared root and `target` is the file in the other universe. The baseline key stays `ruleId|file|fromLayer|toLayer|target` and does not include `reasonId`. A shared hop that stays inside one universe is not this finding. The direct shared-root hop stays the `SHARED_IMPORTS_SLICE` warning. `"deny"` is unchanged and does not emit this reason. Doctor slice counts stay on `CROSS_PARENT_SLICE` and `CROSS_SIBLING_SLICE`. **ark-check and CI report this path. The write hook and ESLint see one edge at a time and do not block it.** A universe edge the importer's rule declares in `allowedCrossSlice` is not reported through a shared root; `childSlices.allowedCrossSlice` never clears it. A composition root listed in `sharedImportsSlice.stopAt` (object form) stops the walk: a path through it is not a crossing. Config load rejects a stop that covers the whole tree or a whole layer root of the rule. Each finding carries `via` (the shared hops); doctor `sharedWalkHubs` names a shared file on at least half of ten or more such findings. `ark-check --changed` runs this pass full-tree when a changed file sits under such a rule's `sharedRoots`. arkgate 4.8.22 and older reject `"deny-cross-parent"` at config load; 4.8.23 and older reject the object form.
|
|
122
135
|
|
|
123
136
|
<a id="LAYER_INTENT_REFERENCE_VIOLATION"></a>
|
|
124
137
|
|
|
@@ -138,6 +151,15 @@ Link form for agents: `docs/diagnostics.md#RULE_ID` (exact-case HTML anchors bel
|
|
|
138
151
|
- **Why:** Snippet analysis found an intent or string reference that would couple layers in a direction the architecture profile forbids.
|
|
139
152
|
- **Fix:** Move the reference to an allowed layer or introduce a port/event boundary, then re-run the snippet gate.
|
|
140
153
|
|
|
154
|
+
<a id="SHARED_IMPORTS_SLICE"></a>
|
|
155
|
+
|
|
156
|
+
### `SHARED_IMPORTS_SLICE`
|
|
157
|
+
|
|
158
|
+
**A shared root imports a slice**
|
|
159
|
+
|
|
160
|
+
- **Why:** A declared shared root imports a slice directly. That hop is allowed while `sharedImportsSlice` is unset or `"deny-cross-parent"`, so this is advisory: the universe wall is direct-only.
|
|
161
|
+
- **Fix:** Move the code the shared root needs into the shared root, or invert the dependency. Set `sharedImportsSlice: "deny"` to make these edges errors. With `"deny-cross-parent"`, a slice that reaches another universe through a shared root is reported as `LAYER_IMPORT_VIOLATION` with `reasonId` `CROSS_PARENT_VIA_SHARED`. `stopAt` does not silence this warning. Advisory — it does not fail the check.
|
|
162
|
+
|
|
141
163
|
<a id="CIRCULAR_DEPENDENCY"></a>
|
|
142
164
|
|
|
143
165
|
### `CIRCULAR_DEPENDENCY`
|
|
@@ -299,6 +321,33 @@ Link form for agents: `docs/diagnostics.md#RULE_ID` (exact-case HTML anchors bel
|
|
|
299
321
|
- **Why:** `orchestration-only`, `thin-adapter`, and `writes-via-aggregate` only evaluate files the hint loader preloaded. When eligible governed files exceed that budget (`coverage.maxFiles`, default `400` — there is no `arkrules.hintBudget`), those sensors never saw the rest of their scope. Enforced + unreviewed is not green. The finding names exact hinted/governed counts and per-sensor reviewed N/M of scope.
|
|
300
322
|
- **Fix:** Raise `coverage.maxFiles` in ark.config.json (this cap also bounds structural-hint preload; `--doctor` names the coupling) so hinted/governed counts match, then re-run with `--strict-config`. An enforced hint sensor that cannot see its scope fails strict.
|
|
301
323
|
|
|
324
|
+
<a id="ARKRULE_FILE_UNREFERENCED"></a>
|
|
325
|
+
|
|
326
|
+
### `ARKRULE_FILE_UNREFERENCED`
|
|
327
|
+
|
|
328
|
+
**ArkRules file not referenced** · often advisory
|
|
329
|
+
|
|
330
|
+
- **Why:** A JSON file under `arkrules/`, or a slice file named `arkrules.<Layer>.json` beside governed code, is not in the effective catalog, so none of its rules are enforced. Drift looks like governance until someone notices.
|
|
331
|
+
- **Fix:** Reference a central file from `arkRules`, set `childSlices.arkRulesFile` so a slice file is discovered, or delete it. Advisory only: it never fails the check.
|
|
332
|
+
|
|
333
|
+
<a id="ARKRULE_DUPLICATE_ID"></a>
|
|
334
|
+
|
|
335
|
+
### `ARKRULE_DUPLICATE_ID`
|
|
336
|
+
|
|
337
|
+
**ArkRule id declared more than once**
|
|
338
|
+
|
|
339
|
+
- **Why:** Two ArkRules files in one layer declare the same effective id. Central ids stay bare. A slice file is namespaced as `<childId>#<localId>`, so the same local id in two slices is not a duplicate.
|
|
340
|
+
- **Fix:** Rename one id, or split the files onto different slices. Config load fails closed. The catalog is not enforced until the id is unique.
|
|
341
|
+
|
|
342
|
+
<a id="ARKRULE_SCOPE_ESCAPES_SLICE"></a>
|
|
343
|
+
|
|
344
|
+
### `ARKRULE_SCOPE_ESCAPES_SLICE`
|
|
345
|
+
|
|
346
|
+
**Slice ArkRule appliesTo leaves its slice**
|
|
347
|
+
|
|
348
|
+
- **Why:** A file discovered from `childSlices.arkRulesFile` set `appliesTo` to a glob that can match outside that child slice. The default, when `appliesTo` is omitted, is the slice directory.
|
|
349
|
+
- **Fix:** Narrow `appliesTo` to the slice directory, or omit it. Config load fails closed. The escaping rule is not enforced.
|
|
350
|
+
|
|
302
351
|
<a id="INVARIANT_CATALOG_EMPTY"></a>
|
|
303
352
|
|
|
304
353
|
### `INVARIANT_CATALOG_EMPTY`
|
|
@@ -314,7 +363,7 @@ Link form for agents: `docs/diagnostics.md#RULE_ID` (exact-case HTML anchors bel
|
|
|
314
363
|
|
|
315
364
|
**Invariant without coverage evidence**
|
|
316
365
|
|
|
317
|
-
- **Why:** An ArkRules invariant is under contract but no covering test title or declared symbol evidence was found (or coverage is partial). A title is a `describe` / `it` / `test` / `context` string. A comment, string, test body, or import that only mentions the id does not count. `coverage.symbol` is a non-test declaration: `function`, `class`, `const`, `method`, `type`, `interface`, or `enum
|
|
366
|
+
- **Why:** An ArkRules invariant is under contract but no covering test title or declared symbol evidence was found (or coverage is partial). A title is a `describe` / `it` / `test` / `context` string. A comment, string, test body, or import that only mentions the id does not count. `coverage.symbol` is a non-test declaration: `function`, `class`, `const`, `method`, `type`, `interface`, or `enum`; a `Class.member` symbol must be a member of `class Class` (or of a `const Class = class {}`, `namespace Class {}`, or `const Class = {}` object literal). An enforced invariant cannot opt out with `coverage.test: false` unless it names a `coverage.symbol`: that shape is reported here as "enforced but declares no evidence". Kind is `never-had-tests` (adopt residual) vs `tests-disappeared` (suite exists). The message names what the scan found.
|
|
318
367
|
- **Fix:** Put the invariant id in a `describe` / `it` title, or declare the `coverage.symbol` name in a non-test file, then preflight again. A comment is not a title — move the id into the `it()` title. Treat never-had-tests as adopt residual; treat tests-disappeared as a regression. Missing test globs report partial — never fake green. When the message reports an exhausted file budget, raise `coverage.maxFiles` (or narrow `coverage.testGlobs`) in ark.config.json. The message also names every file the scan discarded and why (budget, per-file byte cap, unreadable, walk depth limit, symlink resolving outside the project root, no catalogued invariant named) — nothing is dropped in silence.
|
|
319
368
|
|
|
320
369
|
<a id="INVARIANT_COVERAGE_OUTSIDE_ROOTS"></a>
|
|
@@ -339,6 +388,17 @@ Declaring nothing is silent unless any catalogued invariant is enforced — then
|
|
|
339
388
|
|
|
340
389
|
No enforced invariant, or roots already declared, stays silent. This is not a new config key. Promotion to enforced also refuses without roots.
|
|
341
390
|
|
|
391
|
+
<a id="INVARIANT_PROBE_SURVIVED"></a>
|
|
392
|
+
|
|
393
|
+
### `INVARIANT_PROBE_SURVIVED`
|
|
394
|
+
|
|
395
|
+
**Covering tests do not pin the invariant** · often advisory
|
|
396
|
+
|
|
397
|
+
- **Why:** The committed invariant probe (`.ark/invariant-probe.json`, written by `arkgate-check --probe-invariants --write`) shows, for files that have not changed since, that the covering tests still pass with the invariant's `coverage.symbol` broken on purpose (`survived`), or never call it (`not-reached`). The test names the rule but does not pin it.
|
|
398
|
+
- **Fix:** Add a test case that fails when the rule is broken — the line names the change that went unnoticed — then re-run `arkgate-check --probe-invariants --write` and commit the file. Promotion to `enforced` refuses while the fresh artifact says `survived` or `not-reached`.
|
|
399
|
+
|
|
400
|
+
A status (`--doctor`) and `--rules-inventory` line only. It never enters the check, so `valid`, `--strict-merge` and the exit code do not change. A stale row (the symbol file, a covering test or the invariant changed since the run), `killed`, `inconclusive`, `unprobeable`, or no artifact at all changes nothing. The probe is opt-in, runs your own test runner in a temporary copy, and is not a mutation score — see [Probe an invariant](agent-guide.md#probe-an-invariant).
|
|
401
|
+
|
|
342
402
|
<a id="INVARIANT_TESTS_PATH_MISSING"></a>
|
|
343
403
|
|
|
344
404
|
### `INVARIANT_TESTS_PATH_MISSING`
|
|
@@ -355,13 +415,28 @@ Not adopted, no catalogued invariants, or every invariant sets `coverage.test: f
|
|
|
355
415
|
Live adapters specialize `nextAction` with the call-site name or specifier when present
|
|
356
416
|
(casual `enthusiastHint` + engineer `nextAction`). Catalog **Fix** is the stable no-target form.
|
|
357
417
|
|
|
418
|
+
The undeclared-* sensors only count a call whose receiver is **traced to the kernel**: a local
|
|
419
|
+
bound from a kernel factory, an identifier imported from a `kernelRoots` / `compositionRoots`
|
|
420
|
+
module (resolved through tsconfig `paths`, and through barrels that re-export a root), a plain
|
|
421
|
+
alias (`const kernel = ark`) or `typeof ark` binding, a binding typed `ArkKernel` / `EventBus` / `EventPublisher` / `ArkRunPublisher` imported
|
|
422
|
+
from `arkgate/runtime` or `arkgate/nestjs` (including `this.ark` constructor injection), its
|
|
423
|
+
`.eventBus`, a `publisher(..)` result, or destructured kernel members. `res.send`,
|
|
424
|
+
`require.resolve`, `subject.subscribe`, and other same-named methods are not kernel calls — unless
|
|
425
|
+
the receiver cannot be traced (an untyped parameter) **and** the literal name is a kernel-valid
|
|
426
|
+
intent (`Domain.…`, `Application.…`, the only names a kernel accepts); then it counts.
|
|
427
|
+
The call name is a string literal or a same-file `define(..)` / `defineIntent(..)` creator
|
|
428
|
+
(or string constant). When an enforced call names neither (for example an imported creator),
|
|
429
|
+
analysis reports completeness reason `ARKRUN_INTERACTION_NAME_INCOMPLETE` (partial, never green).
|
|
430
|
+
A `publisher(source)` binding without a literal is not incomplete — the emitted name is checked
|
|
431
|
+
on the chained `.publish` / `.send`.
|
|
432
|
+
|
|
358
433
|
<a id="ARKRUN_MISSING_ROOT"></a>
|
|
359
434
|
|
|
360
435
|
### `ARKRUN_MISSING_ROOT`
|
|
361
436
|
|
|
362
437
|
**No kernel factory in composition roots**
|
|
363
438
|
|
|
364
|
-
- **Why:** The ArkRun extra is on but no createArkKernel / createStrictArkKernel /
|
|
439
|
+
- **Why:** The ArkRun extra is on but no kernel factory (createArkKernel / createStrictArkKernel / createLenientArkKernel, their *FromConfig variants, or ArkModule.forRoot / forRootAsync imported from arkgate/nestjs) was found in arkRun.compositionRoots, so agents can skip the kernel while the write gate stays green.
|
|
365
440
|
- **Fix:** Import createStrictArkKernel from arkgate/runtime (same npm package; @arkgate/runtime is deprecated) and call it in a composition root listed in arkRun.compositionRoots, then preflight again. Never mechanical-safe — factory placement is a design decision.
|
|
366
441
|
|
|
367
442
|
<a id="ARKRUN_KERNEL_IN_DOMAIN"></a>
|
|
@@ -370,7 +445,7 @@ Live adapters specialize `nextAction` with the call-site name or specifier when
|
|
|
370
445
|
|
|
371
446
|
**Domain-role layer imports the kernel**
|
|
372
447
|
|
|
373
|
-
- **Why:** A Domain-role layer imports arkgate/runtime, @arkgate/runtime, or kernel types. Domain stays kernel-free; composition roots and adapters own the factory.
|
|
448
|
+
- **Why:** A Domain-role layer imports arkgate/runtime, arkgate/nestjs, @arkgate/runtime, or kernel types. Domain stays kernel-free; composition roots and adapters own the factory.
|
|
374
449
|
- **Fix:** Move the kernel import out of the Domain-role layer into a composition root or adapter. Import from arkgate/runtime (same npm package; @arkgate/runtime is deprecated), then preflight again. Never mechanical-safe.
|
|
375
450
|
|
|
376
451
|
<a id="ARKRUN_DIRECT_NEW"></a>
|
|
@@ -388,7 +463,7 @@ Live adapters specialize `nextAction` with the call-site name or specifier when
|
|
|
388
463
|
|
|
389
464
|
**Emit name not in raises/sends**
|
|
390
465
|
|
|
391
|
-
- **Why:** A publisher / publish / raise / send call
|
|
466
|
+
- **Why:** A publisher / publish / raise / send call on a receiver traced to the kernel names an intent (string literal or same-file define/defineIntent binding) that is not listed in the file’s raises or sends declaration.
|
|
392
467
|
- **Fix:** Add the existing call-site name to raises or sends on the managed component, then preflight again. Mechanical-safe only when that literal already exists and the edit is the declaration list; inventing a new emit stays judgment.
|
|
393
468
|
|
|
394
469
|
<a id="ARKRUN_UNDECLARED_HANDLE"></a>
|
|
@@ -397,7 +472,7 @@ Live adapters specialize `nextAction` with the call-site name or specifier when
|
|
|
397
472
|
|
|
398
473
|
**Handle name not in reactsTo**
|
|
399
474
|
|
|
400
|
-
- **Why:** A subscribe / registerHandler call
|
|
475
|
+
- **Why:** A subscribe / registerHandler call on a receiver traced to the kernel names an intent (string literal or same-file define/defineIntent binding) that is not listed in the file’s reactsTo declaration.
|
|
401
476
|
- **Fix:** Add the existing call-site name to reactsTo on the managed component, then preflight again. Mechanical-safe only when that literal already exists and the edit is the declaration list; inventing a new handle stays judgment.
|
|
402
477
|
|
|
403
478
|
<a id="ARKRUN_UNDECLARED_DEPEND"></a>
|
|
@@ -406,7 +481,7 @@ Live adapters specialize `nextAction` with the call-site name or specifier when
|
|
|
406
481
|
|
|
407
482
|
**Depend name not in uses**
|
|
408
483
|
|
|
409
|
-
- **Why:** A resolve / resolveSingleton call
|
|
484
|
+
- **Why:** A resolve / resolveSingleton call on a receiver traced to the kernel names a component that is not listed in the file’s uses declaration.
|
|
410
485
|
- **Fix:** Add the existing call-site name to uses on the managed component, then preflight again. Mechanical-safe only when that literal already exists and the edit is the declaration list; inventing a new depend stays judgment.
|
|
411
486
|
|
|
412
487
|
<a id="ARKRUN_TRANSPORT_BYPASS"></a>
|
|
@@ -446,7 +521,7 @@ Haken slaving: few slow keys (ξ) determine derived fast state. Field ingest nev
|
|
|
446
521
|
|
|
447
522
|
**Generic update of ξ**
|
|
448
523
|
|
|
449
|
-
- **Why:** A call to update/patch/set on the order plane rewrites the slow pattern. Haken slaving forbids generic ξ mutation.
|
|
524
|
+
- **Why:** A call to update/patch/set on the order plane rewrites the slow pattern. Haken slaving forbids generic ξ mutation. The static sensor only reports a receiver that is a plane on direct evidence: an identifier bound to `createOrderPlane(...)` in the same file, annotated `: OrderPlane`, a `plane` / `*Plane` named import from a declared `planeRoots` module, or a `plane` / `*Plane` name in a file that imports `arkgate/order` (also through `?.`, `!`, or `(x as T)`). A name alone is not evidence: `clipPlane.set(...)` / `controlPlane.update(...)` with no ArkOrder import stay silent, and so do `new Map().set(...)` or `prisma.x.update(...)` in the plane-root file.
|
|
450
525
|
- **Fix:** Use release() for the first freeze of ξ. Later pattern change is proposeRelease then apply(ProposeResult). Never update/patch/set. Never mechanical-safe.
|
|
451
526
|
|
|
452
527
|
<a id="ARKORDER_TOO_MANY_PARAMS"></a>
|
|
@@ -464,7 +539,7 @@ Haken slaving: few slow keys (ξ) determine derived fast state. Field ingest nev
|
|
|
464
539
|
|
|
465
540
|
**ingest assigned into ξ**
|
|
466
541
|
|
|
467
|
-
- **Why:** An ingest() result is written into a Release or ξ store. ingest may absorb, escalate_up, or hold; it never mints a pattern.
|
|
542
|
+
- **Why:** An ingest() result is written into a Release or ξ store. ingest may absorb, escalate_up, or hold; it never mints a pattern. Static evidence is a whole-word `xi` / `release` / `pattern` / `house` / `current` holder, an `xi` camelCase head (`xiNext`), or a `…Xi` / `…Release` / `…Pattern` tail (`nextXi`, `currentRelease`), as a binding or a property write such as `store.xi =` / `this.nextXi =`. Names that only start with those words (`currentResidual`, `patternResult`, `releaseState`) and comparisons (`===`) are not evidence — a deliberate false negative.
|
|
468
543
|
- **Fix:** Keep ingest results as absorb/escalate_up/hold only. Change ξ with proposeRelease then apply(ProposeResult). Never mechanical-safe.
|
|
469
544
|
|
|
470
545
|
<a id="ARKORDER_XI_FIELD_WRITE"></a>
|
|
@@ -473,7 +548,7 @@ Haken slaving: few slow keys (ξ) determine derived fast state. Field ingest nev
|
|
|
473
548
|
|
|
474
549
|
**Slow key written around the order plane**
|
|
475
550
|
|
|
476
|
-
- **Why:** A managed-layer file imports a persistence driver and writes a declared arkOrder.xiKeys name. Field events absorb or escalate; they do not PATCH the slow pattern.
|
|
551
|
+
- **Why:** A managed-layer file imports a persistence driver and writes a declared arkOrder.xiKeys name. Field events absorb or escalate; they do not PATCH the slow pattern. The write must go through a persistence client: `db` / `tx` / `client` / `prisma` / `drizzle`, an inline `new PrismaClient()` / `drizzle(...)`, a name bound in the file to a driver constructor (`const orm = new PrismaClient()`, a class field, or `this.orm = ...`), a name annotated with a driver client type (`constructor(private readonly orm: PrismaClient)`), or a named import from a local `db` / `database` / `prisma` / `drizzle` / `orm` module. `repo.update(...)` and a client from any other module name are not evidence.
|
|
477
552
|
- **Fix:** Keep invoices, seats, hours, and logs on ingest. Change the slow key with proposeRelease then apply(ProposeResult), then preflight again. Never mechanical-safe.
|
|
478
553
|
|
|
479
554
|
<a id="ARKORDER_INFORMATION_BUDGET"></a>
|
|
@@ -482,7 +557,7 @@ Haken slaving: few slow keys (ξ) determine derived fast state. Field ingest nev
|
|
|
482
557
|
|
|
483
558
|
**Projection observes a forbidden kind**
|
|
484
559
|
|
|
485
|
-
- **Why:** h(ξ) allowedKinds includes a kind listed in informationBudget.cannotObserve. A scale may not look at what it was told not to see.
|
|
560
|
+
- **Why:** h(ξ) allowedKinds includes a kind listed in informationBudget.cannotObserve. A scale may not look at what it was told not to see. Static sensor (`arkorder-information-budget`): a literal `allowedKinds: [...]` entry that a literal `cannotObserve: [...]` denies, in a file that calls createOrderPlane; computed arrays stay silent. Runtime: release, proposeRelease, apply, refreshSigma, and restore throw before the Release is offered or persisted; project and ingest re-check.
|
|
486
561
|
- **Fix:** Cut that kind from the projector or from cannotObserve, then preflight again. Never mechanical-safe.
|
|
487
562
|
|
|
488
563
|
<a id="ARKORDER_XI_TTL"></a>
|
|
@@ -491,7 +566,7 @@ Haken slaving: few slow keys (ξ) determine derived fast state. Field ingest nev
|
|
|
491
566
|
|
|
492
567
|
**Slow key carries a freshness field**
|
|
493
568
|
|
|
494
|
-
- **Why:** ξ named ttl/freshUntil/maxAge. Freshness belongs on σ. A slow parameter that expires per transaction is not slow.
|
|
569
|
+
- **Why:** ξ named ttl/freshUntil/maxAge. Freshness belongs on σ. A slow parameter that expires per transaction is not slow. Static sensor (`arkorder-xi-ttl`): such a key (including shorthand `{ plan, ttl }`) in the ξ literal (first argument) of `plane.release({...})` / `plane.proposeRelease({...})` on a plane receiver (same evidence as `ARKORDER_GENERIC_UPDATE`); σ (second argument) may carry freshUntil. The runtime plane throws the same code.
|
|
495
570
|
- **Fix:** Move freshness onto σ (freshUntil) and keep ξ stable, then preflight again. Never mechanical-safe.
|
|
496
571
|
|
|
497
572
|
<a id="ARKORDER_STALE_SIGMA"></a>
|
|
@@ -500,7 +575,7 @@ Haken slaving: few slow keys (ξ) determine derived fast state. Field ingest nev
|
|
|
500
575
|
|
|
501
576
|
**σ is stale**
|
|
502
577
|
|
|
503
|
-
- **Why:** ingest ran after σ.freshUntil (or sigmaMaxAgeMs). ξ does not TTL.
|
|
578
|
+
- **Why:** ingest ran after σ.freshUntil (or sigmaMaxAgeMs). ξ does not TTL. A numeric σ.freshUntil is honored on its own and wins over sigmaMaxAgeMs. Runtime only: ingest returns `hold` with reason `stale-sigma`; this is not a static sensor and `arkOrder.mode` does not promote it.
|
|
504
579
|
- **Fix:** Call refreshSigma and ingest again, or proposeRelease then apply(ProposeResult) if the pattern changed. Never mechanical-safe.
|
|
505
580
|
|
|
506
581
|
<a id="ARKORDER_UNVALVED_RELEASE"></a>
|
|
@@ -512,6 +587,17 @@ Haken slaving: few slow keys (ξ) determine derived fast state. Field ingest nev
|
|
|
512
587
|
- **Why:** release() already froze the big choice. A later release() with a different value does not land. First freeze is release(); later change is proposeRelease then apply.
|
|
513
588
|
- **Fix:** Change the choice with proposeRelease then apply. release() is only the first freeze. Never mechanical-safe.
|
|
514
589
|
|
|
590
|
+
`restore()` raises the same code on a live plane when the Release would change ξ or carry a version other than the current one or the next one (no rollback, no jump).
|
|
591
|
+
|
|
592
|
+
<a id="ARKORDER_STALE_PROPOSAL"></a>
|
|
593
|
+
|
|
594
|
+
### `ARKORDER_STALE_PROPOSAL`
|
|
595
|
+
|
|
596
|
+
**Proposal is not bound to the current Release**
|
|
597
|
+
|
|
598
|
+
- **Why:** apply() got a ProposeResult computed against another Release (another apply landed first), one missing its base binding, or one whose reviewed blast radius is not the transition that would commit. The binding is data, not a capability: a proposal that states the current base and the exact transition applies whoever built it. Runtime only.
|
|
599
|
+
- **Fix:** Run proposeRelease again against the current Release, review the new blast radius, then apply that proposal. Never mechanical-safe.
|
|
600
|
+
|
|
515
601
|
## Atomic preflight and change sets
|
|
516
602
|
|
|
517
603
|
<a id="INVALID_CHANGE_PATH"></a>
|
|
@@ -604,6 +690,15 @@ Haken slaving: few slow keys (ξ) determine derived fast state. Field ingest nev
|
|
|
604
690
|
- **Why:** The host/MCP path could not run the atomic preflight engine (missing facts, incomplete setup, or unsupported mode).
|
|
605
691
|
- **Fix:** Use resolved-candidate facts / ark_prepare_change with a complete batch, or fall back to ark-check on disk. Do not treat missing preflight as green.
|
|
606
692
|
|
|
693
|
+
<a id="WRITE_GATE_UNAVAILABLE"></a>
|
|
694
|
+
|
|
695
|
+
### `WRITE_GATE_UNAVAILABLE`
|
|
696
|
+
|
|
697
|
+
**Write gate could not run**
|
|
698
|
+
|
|
699
|
+
- **Why:** The write gate could not load its own inputs (`ark.config.json` missing, unreadable, or invalid; a referenced ArkRules file missing or invalid; or the built library missing), so it cannot judge this governed source write (existing files included), or a write would leave `ark.config.json` or a referenced ArkRules file unloadable. No checker, no write: the hook blocks instead of letting the write through unchecked.
|
|
700
|
+
- **Fix:** Fix the reported input (repair `ark.config.json` or the ArkRules file, or run `npm run build` / reinstall arkgate from npm), then retry the same write. Do not remove the hook to get past it.
|
|
701
|
+
|
|
607
702
|
<a id="DESIGN_SMELL_REGRESSION"></a>
|
|
608
703
|
|
|
609
704
|
### `DESIGN_SMELL_REGRESSION`
|
|
@@ -631,7 +726,7 @@ Haken slaving: few slow keys (ξ) determine derived fast state. Field ingest nev
|
|
|
631
726
|
**Lexical evidence incomplete**
|
|
632
727
|
|
|
633
728
|
- **Why:** This check only saw one file, so it cannot fully prove how the import resolves. The result is provisional — `ark-check` on the project is the authority.
|
|
634
|
-
- **Fix:**
|
|
729
|
+
- **Fix:** For a complete verdict, run `npx arkgate-check --root . --config ark.config.json` (or `ark_prepare_change` over MCP with the full candidate batch). Read `lexicalValid` for the one-file result. The write hook adds its own hook-only note to its deny text.
|
|
635
730
|
|
|
636
731
|
<a id="ANALYSIS_COVERS_NO_FILES"></a>
|
|
637
732
|
|
|
@@ -696,6 +791,86 @@ by default would be ArkGate's inability to resolve a string presented as a fact
|
|
|
696
791
|
about your code. The count is always printed, so opting out of the list is
|
|
697
792
|
never opting out of knowing.
|
|
698
793
|
|
|
794
|
+
## Files nothing imports
|
|
795
|
+
|
|
796
|
+
Status (`arkgate-check --doctor`) reads the import edges the check already
|
|
797
|
+
resolved. A governed file that nothing imports — no governed file, no test,
|
|
798
|
+
no project script, no known entry point — is listed in status details
|
|
799
|
+
(`--doctor --all`), in `--json` under `doctor.orphanModules`, and in the
|
|
800
|
+
HTML report. The compact status prints one count line at most. It is not a
|
|
801
|
+
score and never changes the check.
|
|
802
|
+
|
|
803
|
+
Entry points come from a closed list: `package.json` (`main`, `module`,
|
|
804
|
+
`types`, `exports`, `bin`, scripts) and CI workflow run steps, framework
|
|
805
|
+
conventions (Next, Vite, Nest, Vercel, Storybook), the arkRun / arkOrder /
|
|
806
|
+
slice-wall roots in `ark.config.json`, config and setup files, ambient
|
|
807
|
+
declaration files, and `.ark/entry-points.json`:
|
|
808
|
+
|
|
809
|
+
```json
|
|
810
|
+
{
|
|
811
|
+
"schemaVersion": "1",
|
|
812
|
+
"entryPoints": [
|
|
813
|
+
{ "glob": "src/plugins/**", "reason": "loaded by name at runtime", "reviewBy": "2027-01-01" }
|
|
814
|
+
]
|
|
815
|
+
}
|
|
816
|
+
```
|
|
817
|
+
|
|
818
|
+
<a id="ORPHAN_MODULE"></a>
|
|
819
|
+
|
|
820
|
+
### `ORPHAN_MODULE`
|
|
821
|
+
|
|
822
|
+
**File nothing imports** · often advisory
|
|
823
|
+
|
|
824
|
+
- **Why:** No governed file, test or entry point imports this module. It is the leftover an agent leaves when a rewrite lands next to the old file. Status reads it from the import facts the check already resolved, so it never changes the verdict. When a dynamic import, an unresolved import or an unmapped entry could reach the file, the item says so (`maybe-dynamic`, `maybe-unresolved`) and the list is `partial`.
|
|
825
|
+
- **Fix:** Delete the file through the write gate, one file at a time. If a framework, a script or a runtime loader uses it, add a glob with a reason to `.ark/entry-points.json` (optional `reviewBy`) instead. Advisory only — it never fails a run.
|
|
826
|
+
|
|
827
|
+
<a id="UNUSED_EXPORT"></a>
|
|
828
|
+
|
|
829
|
+
### `UNUSED_EXPORT`
|
|
830
|
+
|
|
831
|
+
**Export nothing imports by name** · often advisory
|
|
832
|
+
|
|
833
|
+
- **Why:** An export no governed file or test imports by name. Listed only in status details (`--doctor --all`) and the report. Default, namespace, star, dynamic and require use count as using every export, so those files are skipped.
|
|
834
|
+
- **Fix:** Drop the export keyword (or the code) if nothing outside the file needs it, or keep it when it is public API an entry point exposes. Advisory only — it never fails a run.
|
|
835
|
+
|
|
836
|
+
## Copies across a wall
|
|
837
|
+
|
|
838
|
+
A slice wall denies the import. The cheapest way around it is to copy the
|
|
839
|
+
code, and a copy is not an import. Status details (`arkgate-check --doctor --all`)
|
|
840
|
+
and the HTML report list near-identical code whose copies sit on two sides of
|
|
841
|
+
a wall, or in two layers, with a place the shared code could live. `--json`
|
|
842
|
+
carries it under `doctor.crossWallDuplication`; without `--all` it says
|
|
843
|
+
`not-run` and names the command. It is not a score and never changes the check.
|
|
844
|
+
|
|
845
|
+
The copies come from token fingerprints taken while status runs: one parse per
|
|
846
|
+
governed file with the TypeScript ArkGate already loaded. Tests, `.d.ts`,
|
|
847
|
+
generated files (default globs, or a `@generated` / `GENERATED FILE` /
|
|
848
|
+
`DO NOT EDIT` header in the first five lines) and files over 256 KB are never
|
|
849
|
+
read for this. A copy is listed only when the import between its two files is
|
|
850
|
+
one the check would deny, or when it sits in two layers. Copies inside one
|
|
851
|
+
slice are counted, never listed. A path the wall cannot classify is counted,
|
|
852
|
+
never listed. The constants are fixed: at least 50 tokens and 5 lines, and at
|
|
853
|
+
least 60% of the names matching. When a cap stops the pass, the section says
|
|
854
|
+
`partial` and how much was left.
|
|
855
|
+
|
|
856
|
+
<a id="CROSS_WALL_DUPLICATE"></a>
|
|
857
|
+
|
|
858
|
+
### `CROSS_WALL_DUPLICATE`
|
|
859
|
+
|
|
860
|
+
**Code copied across a wall** · often advisory
|
|
861
|
+
|
|
862
|
+
- **Why:** Near-identical code sits on two sides of a slice wall (`cross-slice`, `cross-parent`, `cross-sibling`) or in two layers that may not import each other (`cross-layer-walled`). The wall would deny the import, so the code was copied instead. Fingerprints are taken at status time and never enter the check, so the verdict does not change.
|
|
863
|
+
- **Fix:** Move one copy to a shared home the wall allows — the declared shared root, the universe common folder, or a layer both sides may import — then import it from both sides. One move at a time, through the write gate (`/ark-place` names the destination). Advisory only — it never fails a run.
|
|
864
|
+
|
|
865
|
+
<a id="CROSS_LAYER_DUPLICATE"></a>
|
|
866
|
+
|
|
867
|
+
### `CROSS_LAYER_DUPLICATE`
|
|
868
|
+
|
|
869
|
+
**Code copied in two layers** · often advisory
|
|
870
|
+
|
|
871
|
+
- **Why:** Near-identical code sits in two layers, and at least one of them may import the other (`cross-layer`).
|
|
872
|
+
- **Fix:** Keep one copy in the lower layer both sides may import, and import it from the other. One move at a time, through the write gate. Advisory only — it never fails a run.
|
|
873
|
+
|
|
699
874
|
## Port adapters
|
|
700
875
|
|
|
701
876
|
<a id="ADAPTER_NOT_ALLOWED_FOR_PORT"></a>
|
|
@@ -913,10 +1088,10 @@ never opting out of knowing.
|
|
|
913
1088
|
|
|
914
1089
|
### `CONFIG_CHILD_SLICES_VERSION`
|
|
915
1090
|
|
|
916
|
-
**
|
|
1091
|
+
**Config needs a newer arkgate than a pinned copy**
|
|
917
1092
|
|
|
918
|
-
- **Why:**
|
|
919
|
-
- **Fix:**
|
|
1093
|
+
- **Why:** `ark.config.json` uses a slice key (`childSlices`, `sharedImportsSlice` `"deny-cross-parent"` or its object form, `sliceIdentity`, `sharedImportsSlice`, `childSlices.message`, `siblings.ratchet`) that an arkgate pinned in this repo rejects at config load. Emitted only with evidence of that pin: an exact `package.json` dependency, the installed `node_modules/arkgate`, `package-lock.json`, a `scripts/*hook*` or host hook command, or a CI workflow. Silent otherwise. The finding's location is that file and line.
|
|
1094
|
+
- **Fix:** Bump the named file to the version the finding's `nextAction` gives (or newer), then run Ark again. This warning does not fail the check.
|
|
920
1095
|
|
|
921
1096
|
<a id="CONFIG_CHILD_SLICE_EXTENDS"></a>
|
|
922
1097
|
|
|
@@ -936,6 +1111,24 @@ never opting out of knowing.
|
|
|
936
1111
|
- **Why:** childSlices.allowedCrossSlice names a pattern that can match two universes. That list clears only a sibling crossing inside one universe. The universe wall still denies the edge.
|
|
937
1112
|
- **Fix:** Narrow the pattern so both sides share one universe prefix (features/projects/* to features/projects/d2d-item), or remove the entry. This warning does not fail the check.
|
|
938
1113
|
|
|
1114
|
+
<a id="CONFIG_CHILD_SLICES_INERT"></a>
|
|
1115
|
+
|
|
1116
|
+
### `CONFIG_CHILD_SLICES_INERT`
|
|
1117
|
+
|
|
1118
|
+
**childSlices on a rule that cannot run it**
|
|
1119
|
+
|
|
1120
|
+
- **Why:** A rule sets childSlices without peerIsolation: true and allowed: false. The child wall runs only inside a universe wall, so on this rule childSlices enforces nothing. Config load still accepts it (arkgate 4.8.23 did too).
|
|
1121
|
+
- **Fix:** Add "peerIsolation": true and "allowed": false to the same rule so the child wall runs, or remove childSlices. This warning does not fail the check.
|
|
1122
|
+
|
|
1123
|
+
<a id="CONFIG_SLICE_LEGACY_STARS_ID"></a>
|
|
1124
|
+
|
|
1125
|
+
### `CONFIG_SLICE_LEGACY_STARS_ID`
|
|
1126
|
+
|
|
1127
|
+
**Slice id written in the 4.8.23 stars form**
|
|
1128
|
+
|
|
1129
|
+
- **Why:** Under sliceIdentity "stars", a sliceAliases target or an allowedCrossSlice entry names the 4.8.23 stars id, which dropped a star binding before the last literal (modules/*/api/* bound api/v1). The id now keeps that binding (orders/api/v1). For one release the entry keeps its 4.8.23 meaning, so verdicts do not change.
|
|
1130
|
+
- **Fix:** Rewrite the entry with the new id the warning names (for example orders/api/v1/x instead of api/v1/x). A sliceAliases target that maps to more than one universe shape is rejected at config load. This warning does not fail the check.
|
|
1131
|
+
|
|
939
1132
|
## Meta
|
|
940
1133
|
|
|
941
1134
|
<a id="ARK_UNKNOWN"></a>
|