arkgate 4.8.22 → 4.8.24
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 +91 -0
- package/README.md +7 -5
- package/bin/ark-check-runtime.mjs +27 -78
- package/bin/ark-dashboard.mjs +56 -53
- package/bin/ark-layer-match.mjs +1117 -38
- package/bin/ark-mcp-runtime.mjs +412 -138
- package/bin/ark-mcp.mjs +68 -4
- package/bin/ark-shared.mjs +39 -0
- 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/agent-projection-command.mjs +5 -1
- package/bin/lib/analysis-engine.mjs +15 -11
- package/bin/lib/architecture-scan.mjs +50 -6
- package/bin/lib/ark-order-doctor.mjs +1 -1
- package/bin/lib/ark-order-facts.mjs +410 -15
- package/bin/lib/ark-order-invariants.mjs +51 -9
- package/bin/lib/ark-order-sensors.mjs +28 -101
- package/bin/lib/ark-order-types.mjs +2 -0
- package/bin/lib/ark-run-doctor.mjs +14 -0
- package/bin/lib/ark-run-facts.mjs +434 -11
- package/bin/lib/ark-run-sensors.mjs +5 -3
- package/bin/lib/arkgate-pins.mjs +91 -0
- package/bin/lib/arkrules-sensors.mjs +50 -249
- package/bin/lib/check-args.mjs +23 -1
- package/bin/lib/ci-and-commands.mjs +16 -6
- package/bin/lib/class-source-scan.mjs +479 -0
- package/bin/lib/codex-home.mjs +4 -2
- package/bin/lib/config-contract-slices.mjs +701 -0
- package/bin/lib/config-contract.mjs +5 -2
- package/bin/lib/config-warnings.mjs +32 -0
- package/bin/lib/dashboard-cli.mjs +62 -0
- package/bin/lib/design-delta.mjs +1 -1
- package/bin/lib/diagnostic-catalog.mjs +45 -6
- package/bin/lib/doctor-advisories.mjs +84 -1
- package/bin/lib/doctor-next-actions.mjs +17 -2
- package/bin/lib/doctor-plan.mjs +7 -9
- package/bin/lib/effective-contract-load.mjs +121 -59
- package/bin/lib/enforcement-honesty.mjs +22 -0
- package/bin/lib/enforcement-profiles.mjs +40 -4
- package/bin/lib/first-run-help.mjs +3 -2
- package/bin/lib/flat-parent-importers.mjs +137 -0
- package/bin/lib/flat-parent-pilot.mjs +192 -0
- package/bin/lib/gate-files.mjs +29 -2
- package/bin/lib/git-change-scope.mjs +109 -0
- package/bin/lib/github-enforcement.mjs +1 -1
- package/bin/lib/hook-templates.mjs +18 -16
- package/bin/lib/host-support-matrix.mjs +3 -1
- package/bin/lib/html-report-advisories.mjs +2 -0
- package/bin/lib/html-report-depth.mjs +3 -1
- package/bin/lib/import-resolve.mjs +13 -1
- package/bin/lib/install-migrate.mjs +50 -73
- package/bin/lib/invariant-coverage.mjs +59 -11
- package/bin/lib/mcp-adoption.mjs +9 -1
- package/bin/lib/mcp-hook-payload.mjs +401 -61
- package/bin/lib/package-manager.mjs +59 -1
- package/bin/lib/passthrough-commands.mjs +83 -0
- package/bin/lib/persistence-write-hint.mjs +81 -0
- package/bin/lib/physical-cohesion.mjs +16 -18
- package/bin/lib/pilot-loop.mjs +21 -8
- package/bin/lib/pin-dependent-gates.mjs +117 -0
- package/bin/lib/policy-delta-io.mjs +168 -10
- package/bin/lib/prepare-change.mjs +120 -6
- package/bin/lib/prepare-write.mjs +1 -0
- package/bin/lib/presets.mjs +3 -5
- package/bin/lib/remediation.mjs +23 -4
- package/bin/lib/resolved-candidate-facts.mjs +315 -55
- package/bin/lib/rules-inventory.mjs +22 -3
- package/bin/lib/rules-under-contract.mjs +179 -5
- package/bin/lib/scan-files.mjs +32 -0
- package/bin/lib/snippet-analysis.mjs +140 -6
- package/bin/lib/source-policy.mjs +34 -0
- package/bin/lib/stable-hash.mjs +90 -0
- package/bin/lib/start-install-recovery.mjs +71 -1
- package/bin/lib/start-preview.mjs +30 -0
- package/bin/lib/status-command.mjs +33 -4
- package/bin/lib/status-manifest.mjs +32 -4
- package/bin/lib/team-parliament-io.mjs +79 -75
- package/bin/lib/team-parliament.mjs +6 -1
- package/bin/lib/write-path-capabilities.mjs +4 -2
- package/dist/chunk-A5EIY3HI.cjs +5 -0
- package/dist/chunk-MBXCFLO4.js +16 -0
- package/dist/chunk-RNQHRDCQ.cjs +16 -0
- package/dist/chunk-SVSQVGFJ.js +5 -0
- package/dist/{configTypes-CTELo87-.d.ts → configTypes-BJbaeoj4.d.cts} +53 -4
- package/dist/configTypes-BJbaeoj4.d.ts +246 -0
- package/dist/eslint/index.cjs +17 -4
- package/dist/eslint/index.d.cts +359 -0
- package/dist/eslint/index.d.ts +178 -158
- package/dist/eslint/index.js +10 -4
- package/dist/index.cjs +38 -37
- package/dist/index.d.cts +5475 -0
- package/dist/index.d.ts +3408 -296
- package/dist/index.js +38 -37
- 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-WD2TPSwZ.d.ts → runtime/index.d.cts} +814 -290
- package/dist/runtime/index.d.ts +2678 -108
- package/dist/runtime/index.js +13 -30
- package/dist/{types-yDNEQ603.d.ts → types-DRinG-vT.d.cts} +576 -140
- package/dist/types-DRinG-vT.d.ts +1792 -0
- package/docs/README.md +3 -1
- package/docs/agent-guide.md +92 -15
- package/docs/ai-gates.md +160 -26
- package/docs/arkorder.md +32 -15
- package/docs/brownfield-adoption.md +5 -1
- package/docs/configuration.md +273 -12
- package/docs/develop.md +2 -1
- package/docs/diagnostics.md +122 -13
- package/docs/package-surface.md +31 -8
- package/docs/product-voice.md +1 -1
- package/package.json +59 -18
- package/schemas/ark.analysis-result.schema.json +15 -0
- package/schemas/ark.config.schema.json +163 -4
- 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 +4 -1
- package/templates/agent-skills/ark-order/SKILL.md +4 -2
- 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 +4 -1
- package/templates/skills/ark-order.md +4 -2
- package/templates/skills/ark-runtime.md +6 -1
- package/dist/types-fQ9-KrBj.d.ts +0 -183
package/docs/diagnostics.md
CHANGED
|
@@ -27,6 +27,7 @@ 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 |
|
|
31
32
|
| [`FORBIDDEN_GLOBAL`](#FORBIDDEN_GLOBAL) | capability | Forbidden ambient global or dual import |
|
|
32
33
|
| [`CAPABILITY_VIOLATION`](#CAPABILITY_VIOLATION) | capability | Denied effect capability |
|
|
@@ -44,6 +45,7 @@ Link form for agents: `docs/diagnostics.md#RULE_ID` (exact-case HTML anchors bel
|
|
|
44
45
|
| [`ARKRULE_INVARIANT`](#ARKRULE_INVARIANT) | arkrules | ArkRule invariant failed |
|
|
45
46
|
| [`ARKRULE_SCOPE_EMPTY`](#ARKRULE_SCOPE_EMPTY) | arkrules | ArkRule appliesTo matched zero files |
|
|
46
47
|
| [`ARKRULE_HINT_BUDGET_EXHAUSTED`](#ARKRULE_HINT_BUDGET_EXHAUSTED) | arkrules | Structural-hint budget exhausted |
|
|
48
|
+
| [`ARKRULE_FILE_UNREFERENCED`](#ARKRULE_FILE_UNREFERENCED) | arkrules | ArkRules file not referenced |
|
|
47
49
|
| [`INVARIANT_CATALOG_EMPTY`](#INVARIANT_CATALOG_EMPTY) | arkrules | Domain invariant catalog is empty |
|
|
48
50
|
| [`INVARIANT_UNCOVERED`](#INVARIANT_UNCOVERED) | arkrules | Invariant without coverage evidence |
|
|
49
51
|
| [`INVARIANT_COVERAGE_OUTSIDE_ROOTS`](#INVARIANT_COVERAGE_OUTSIDE_ROOTS) | arkrules | Covering test outside the declared coverage roots |
|
|
@@ -62,6 +64,7 @@ Link form for agents: `docs/diagnostics.md#RULE_ID` (exact-case HTML anchors bel
|
|
|
62
64
|
| [`ARKORDER_TOO_MANY_PARAMS`](#ARKORDER_TOO_MANY_PARAMS) | arkorder | Too many slow keys |
|
|
63
65
|
| [`ARKORDER_INGEST_WRITES_XI`](#ARKORDER_INGEST_WRITES_XI) | arkorder | ingest assigned into ξ |
|
|
64
66
|
| [`ARKORDER_UNVALVED_RELEASE`](#ARKORDER_UNVALVED_RELEASE) | arkorder | Second freeze without the valve |
|
|
67
|
+
| [`ARKORDER_STALE_PROPOSAL`](#ARKORDER_STALE_PROPOSAL) | arkorder | Proposal is not bound to the current Release |
|
|
65
68
|
| [`INVALID_CHANGE_PATH`](#INVALID_CHANGE_PATH) | preflight | Unsafe change path |
|
|
66
69
|
| [`DUPLICATE_CHANGE_PATH`](#DUPLICATE_CHANGE_PATH) | preflight | Duplicate path in change set |
|
|
67
70
|
| [`DELETE_TARGET_MISSING`](#DELETE_TARGET_MISSING) | preflight | Delete target missing |
|
|
@@ -72,6 +75,7 @@ Link form for agents: `docs/diagnostics.md#RULE_ID` (exact-case HTML anchors bel
|
|
|
72
75
|
| [`CANDIDATE_CONTENT_HASH_MISMATCH`](#CANDIDATE_CONTENT_HASH_MISMATCH) | preflight | Candidate content hash mismatch |
|
|
73
76
|
| [`UNDECLARED_CANDIDATE_CHANGE`](#UNDECLARED_CANDIDATE_CHANGE) | preflight | Undeclared candidate change |
|
|
74
77
|
| [`ATOMIC_PREFLIGHT_UNAVAILABLE`](#ATOMIC_PREFLIGHT_UNAVAILABLE) | preflight | Atomic preflight unavailable |
|
|
78
|
+
| [`WRITE_GATE_UNAVAILABLE`](#WRITE_GATE_UNAVAILABLE) | preflight | Write gate could not run |
|
|
75
79
|
| [`DESIGN_SMELL_REGRESSION`](#DESIGN_SMELL_REGRESSION) | preflight | Design smell regression on base-relative ratchet |
|
|
76
80
|
| [`ANALYSIS_PARSE_INCOMPLETE`](#ANALYSIS_PARSE_INCOMPLETE) | analysis | Parse incomplete |
|
|
77
81
|
| [`LEXICAL_EVIDENCE_INCOMPLETE`](#LEXICAL_EVIDENCE_INCOMPLETE) | analysis | Lexical evidence incomplete |
|
|
@@ -102,6 +106,11 @@ Link form for agents: `docs/diagnostics.md#RULE_ID` (exact-case HTML anchors bel
|
|
|
102
106
|
| [`CONFIG_UNCLASSIFIED_FILES`](#CONFIG_UNCLASSIFIED_FILES) | config | Unclassified included files |
|
|
103
107
|
| [`CONFIG_LAYER_MISSING_OWNER`](#CONFIG_LAYER_MISSING_OWNER) | config | Layer missing owner |
|
|
104
108
|
| [`CONFIG_SLICE_IDENTITY_COLLISION`](#CONFIG_SLICE_IDENTITY_COLLISION) | config | Starred slice prefixes share one id |
|
|
109
|
+
| [`CONFIG_CHILD_SLICES_VERSION`](#CONFIG_CHILD_SLICES_VERSION) | config | Config needs a newer arkgate than a pinned copy |
|
|
110
|
+
| [`CONFIG_CHILD_SLICE_EXTENDS`](#CONFIG_CHILD_SLICE_EXTENDS) | config | Child slice id does not extend its universe |
|
|
111
|
+
| [`CONFIG_CHILD_SLICE_CROSS_UNIVERSE`](#CONFIG_CHILD_SLICE_CROSS_UNIVERSE) | config | Child slice allowance cannot cross the universe wall |
|
|
112
|
+
| [`CONFIG_CHILD_SLICES_INERT`](#CONFIG_CHILD_SLICES_INERT) | config | childSlices on a rule that cannot run it |
|
|
113
|
+
| [`CONFIG_SLICE_LEGACY_STARS_ID`](#CONFIG_SLICE_LEGACY_STARS_ID) | config | Slice id written in the 4.8.23 stars form |
|
|
105
114
|
| [`ARK_UNKNOWN`](#ARK_UNKNOWN) | meta | Unknown diagnostic |
|
|
106
115
|
|
|
107
116
|
## Layer and dependency graph
|
|
@@ -114,6 +123,8 @@ Link form for agents: `docs/diagnostics.md#RULE_ID` (exact-case HTML anchors bel
|
|
|
114
123
|
|
|
115
124
|
- **Why:** This file imported a folder it may not reach. The write doesn’t land. The same check fails the pull request.
|
|
116
125
|
- **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.
|
|
126
|
+
- **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.
|
|
127
|
+
- **`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.
|
|
117
128
|
|
|
118
129
|
<a id="LAYER_INTENT_REFERENCE_VIOLATION"></a>
|
|
119
130
|
|
|
@@ -133,6 +144,15 @@ Link form for agents: `docs/diagnostics.md#RULE_ID` (exact-case HTML anchors bel
|
|
|
133
144
|
- **Why:** Snippet analysis found an intent or string reference that would couple layers in a direction the architecture profile forbids.
|
|
134
145
|
- **Fix:** Move the reference to an allowed layer or introduce a port/event boundary, then re-run the snippet gate.
|
|
135
146
|
|
|
147
|
+
<a id="SHARED_IMPORTS_SLICE"></a>
|
|
148
|
+
|
|
149
|
+
### `SHARED_IMPORTS_SLICE`
|
|
150
|
+
|
|
151
|
+
**A shared root imports a slice**
|
|
152
|
+
|
|
153
|
+
- **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.
|
|
154
|
+
- **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.
|
|
155
|
+
|
|
136
156
|
<a id="CIRCULAR_DEPENDENCY"></a>
|
|
137
157
|
|
|
138
158
|
### `CIRCULAR_DEPENDENCY`
|
|
@@ -294,6 +314,15 @@ Link form for agents: `docs/diagnostics.md#RULE_ID` (exact-case HTML anchors bel
|
|
|
294
314
|
- **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.
|
|
295
315
|
- **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.
|
|
296
316
|
|
|
317
|
+
<a id="ARKRULE_FILE_UNREFERENCED"></a>
|
|
318
|
+
|
|
319
|
+
### `ARKRULE_FILE_UNREFERENCED`
|
|
320
|
+
|
|
321
|
+
**ArkRules file not referenced** · often advisory
|
|
322
|
+
|
|
323
|
+
- **Why:** A JSON file under `arkrules/` is not referenced by the `arkRules` map in ark.config.json (or no map exists), so none of its rules are enforced or reported. Drift looks like governance until someone notices.
|
|
324
|
+
- **Fix:** Reference the file from `arkRules` (`"<Layer>": "arkrules/<file>.json"`), or delete it. Advisory only: it never fails the check.
|
|
325
|
+
|
|
297
326
|
<a id="INVARIANT_CATALOG_EMPTY"></a>
|
|
298
327
|
|
|
299
328
|
### `INVARIANT_CATALOG_EMPTY`
|
|
@@ -309,7 +338,7 @@ Link form for agents: `docs/diagnostics.md#RULE_ID` (exact-case HTML anchors bel
|
|
|
309
338
|
|
|
310
339
|
**Invariant without coverage evidence**
|
|
311
340
|
|
|
312
|
-
- **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
|
|
341
|
+
- **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.
|
|
313
342
|
- **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.
|
|
314
343
|
|
|
315
344
|
<a id="INVARIANT_COVERAGE_OUTSIDE_ROOTS"></a>
|
|
@@ -350,13 +379,28 @@ Not adopted, no catalogued invariants, or every invariant sets `coverage.test: f
|
|
|
350
379
|
Live adapters specialize `nextAction` with the call-site name or specifier when present
|
|
351
380
|
(casual `enthusiastHint` + engineer `nextAction`). Catalog **Fix** is the stable no-target form.
|
|
352
381
|
|
|
382
|
+
The undeclared-* sensors only count a call whose receiver is **traced to the kernel**: a local
|
|
383
|
+
bound from a kernel factory, an identifier imported from a `kernelRoots` / `compositionRoots`
|
|
384
|
+
module (resolved through tsconfig `paths`, and through barrels that re-export a root), a plain
|
|
385
|
+
alias (`const kernel = ark`) or `typeof ark` binding, a binding typed `ArkKernel` / `EventBus` / `EventPublisher` / `ArkRunPublisher` imported
|
|
386
|
+
from `arkgate/runtime` or `arkgate/nestjs` (including `this.ark` constructor injection), its
|
|
387
|
+
`.eventBus`, a `publisher(..)` result, or destructured kernel members. `res.send`,
|
|
388
|
+
`require.resolve`, `subject.subscribe`, and other same-named methods are not kernel calls — unless
|
|
389
|
+
the receiver cannot be traced (an untyped parameter) **and** the literal name is a kernel-valid
|
|
390
|
+
intent (`Domain.…`, `Application.…`, the only names a kernel accepts); then it counts.
|
|
391
|
+
The call name is a string literal or a same-file `define(..)` / `defineIntent(..)` creator
|
|
392
|
+
(or string constant). When an enforced call names neither (for example an imported creator),
|
|
393
|
+
analysis reports completeness reason `ARKRUN_INTERACTION_NAME_INCOMPLETE` (partial, never green).
|
|
394
|
+
A `publisher(source)` binding without a literal is not incomplete — the emitted name is checked
|
|
395
|
+
on the chained `.publish` / `.send`.
|
|
396
|
+
|
|
353
397
|
<a id="ARKRUN_MISSING_ROOT"></a>
|
|
354
398
|
|
|
355
399
|
### `ARKRUN_MISSING_ROOT`
|
|
356
400
|
|
|
357
401
|
**No kernel factory in composition roots**
|
|
358
402
|
|
|
359
|
-
- **Why:** The ArkRun extra is on but no createArkKernel / createStrictArkKernel /
|
|
403
|
+
- **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.
|
|
360
404
|
- **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.
|
|
361
405
|
|
|
362
406
|
<a id="ARKRUN_KERNEL_IN_DOMAIN"></a>
|
|
@@ -365,7 +409,7 @@ Live adapters specialize `nextAction` with the call-site name or specifier when
|
|
|
365
409
|
|
|
366
410
|
**Domain-role layer imports the kernel**
|
|
367
411
|
|
|
368
|
-
- **Why:** A Domain-role layer imports arkgate/runtime, @arkgate/runtime, or kernel types. Domain stays kernel-free; composition roots and adapters own the factory.
|
|
412
|
+
- **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.
|
|
369
413
|
- **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.
|
|
370
414
|
|
|
371
415
|
<a id="ARKRUN_DIRECT_NEW"></a>
|
|
@@ -383,7 +427,7 @@ Live adapters specialize `nextAction` with the call-site name or specifier when
|
|
|
383
427
|
|
|
384
428
|
**Emit name not in raises/sends**
|
|
385
429
|
|
|
386
|
-
- **Why:** A publisher / publish / raise / send call
|
|
430
|
+
- **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.
|
|
387
431
|
- **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.
|
|
388
432
|
|
|
389
433
|
<a id="ARKRUN_UNDECLARED_HANDLE"></a>
|
|
@@ -392,7 +436,7 @@ Live adapters specialize `nextAction` with the call-site name or specifier when
|
|
|
392
436
|
|
|
393
437
|
**Handle name not in reactsTo**
|
|
394
438
|
|
|
395
|
-
- **Why:** A subscribe / registerHandler call
|
|
439
|
+
- **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.
|
|
396
440
|
- **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.
|
|
397
441
|
|
|
398
442
|
<a id="ARKRUN_UNDECLARED_DEPEND"></a>
|
|
@@ -401,7 +445,7 @@ Live adapters specialize `nextAction` with the call-site name or specifier when
|
|
|
401
445
|
|
|
402
446
|
**Depend name not in uses**
|
|
403
447
|
|
|
404
|
-
- **Why:** A resolve / resolveSingleton call
|
|
448
|
+
- **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.
|
|
405
449
|
- **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.
|
|
406
450
|
|
|
407
451
|
<a id="ARKRUN_TRANSPORT_BYPASS"></a>
|
|
@@ -441,7 +485,7 @@ Haken slaving: few slow keys (ξ) determine derived fast state. Field ingest nev
|
|
|
441
485
|
|
|
442
486
|
**Generic update of ξ**
|
|
443
487
|
|
|
444
|
-
- **Why:** A call to update/patch/set on the order plane rewrites the slow pattern. Haken slaving forbids generic ξ mutation.
|
|
488
|
+
- **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.
|
|
445
489
|
- **Fix:** Use release() for the first freeze of ξ. Later pattern change is proposeRelease then apply(ProposeResult). Never update/patch/set. Never mechanical-safe.
|
|
446
490
|
|
|
447
491
|
<a id="ARKORDER_TOO_MANY_PARAMS"></a>
|
|
@@ -459,7 +503,7 @@ Haken slaving: few slow keys (ξ) determine derived fast state. Field ingest nev
|
|
|
459
503
|
|
|
460
504
|
**ingest assigned into ξ**
|
|
461
505
|
|
|
462
|
-
- **Why:** An ingest() result is written into a Release or ξ store. ingest may absorb, escalate_up, or hold; it never mints a pattern.
|
|
506
|
+
- **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.
|
|
463
507
|
- **Fix:** Keep ingest results as absorb/escalate_up/hold only. Change ξ with proposeRelease then apply(ProposeResult). Never mechanical-safe.
|
|
464
508
|
|
|
465
509
|
<a id="ARKORDER_XI_FIELD_WRITE"></a>
|
|
@@ -468,7 +512,7 @@ Haken slaving: few slow keys (ξ) determine derived fast state. Field ingest nev
|
|
|
468
512
|
|
|
469
513
|
**Slow key written around the order plane**
|
|
470
514
|
|
|
471
|
-
- **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.
|
|
515
|
+
- **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.
|
|
472
516
|
- **Fix:** Keep invoices, seats, hours, and logs on ingest. Change the slow key with proposeRelease then apply(ProposeResult), then preflight again. Never mechanical-safe.
|
|
473
517
|
|
|
474
518
|
<a id="ARKORDER_INFORMATION_BUDGET"></a>
|
|
@@ -477,7 +521,7 @@ Haken slaving: few slow keys (ξ) determine derived fast state. Field ingest nev
|
|
|
477
521
|
|
|
478
522
|
**Projection observes a forbidden kind**
|
|
479
523
|
|
|
480
|
-
- **Why:** h(ξ) allowedKinds includes a kind listed in informationBudget.cannotObserve. A scale may not look at what it was told not to see.
|
|
524
|
+
- **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.
|
|
481
525
|
- **Fix:** Cut that kind from the projector or from cannotObserve, then preflight again. Never mechanical-safe.
|
|
482
526
|
|
|
483
527
|
<a id="ARKORDER_XI_TTL"></a>
|
|
@@ -486,7 +530,7 @@ Haken slaving: few slow keys (ξ) determine derived fast state. Field ingest nev
|
|
|
486
530
|
|
|
487
531
|
**Slow key carries a freshness field**
|
|
488
532
|
|
|
489
|
-
- **Why:** ξ named ttl/freshUntil/maxAge. Freshness belongs on σ. A slow parameter that expires per transaction is not slow.
|
|
533
|
+
- **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.
|
|
490
534
|
- **Fix:** Move freshness onto σ (freshUntil) and keep ξ stable, then preflight again. Never mechanical-safe.
|
|
491
535
|
|
|
492
536
|
<a id="ARKORDER_STALE_SIGMA"></a>
|
|
@@ -495,7 +539,7 @@ Haken slaving: few slow keys (ξ) determine derived fast state. Field ingest nev
|
|
|
495
539
|
|
|
496
540
|
**σ is stale**
|
|
497
541
|
|
|
498
|
-
- **Why:** ingest ran after σ.freshUntil (or sigmaMaxAgeMs). ξ does not TTL.
|
|
542
|
+
- **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.
|
|
499
543
|
- **Fix:** Call refreshSigma and ingest again, or proposeRelease then apply(ProposeResult) if the pattern changed. Never mechanical-safe.
|
|
500
544
|
|
|
501
545
|
<a id="ARKORDER_UNVALVED_RELEASE"></a>
|
|
@@ -507,6 +551,17 @@ Haken slaving: few slow keys (ξ) determine derived fast state. Field ingest nev
|
|
|
507
551
|
- **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.
|
|
508
552
|
- **Fix:** Change the choice with proposeRelease then apply. release() is only the first freeze. Never mechanical-safe.
|
|
509
553
|
|
|
554
|
+
`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).
|
|
555
|
+
|
|
556
|
+
<a id="ARKORDER_STALE_PROPOSAL"></a>
|
|
557
|
+
|
|
558
|
+
### `ARKORDER_STALE_PROPOSAL`
|
|
559
|
+
|
|
560
|
+
**Proposal is not bound to the current Release**
|
|
561
|
+
|
|
562
|
+
- **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.
|
|
563
|
+
- **Fix:** Run proposeRelease again against the current Release, review the new blast radius, then apply that proposal. Never mechanical-safe.
|
|
564
|
+
|
|
510
565
|
## Atomic preflight and change sets
|
|
511
566
|
|
|
512
567
|
<a id="INVALID_CHANGE_PATH"></a>
|
|
@@ -599,6 +654,15 @@ Haken slaving: few slow keys (ξ) determine derived fast state. Field ingest nev
|
|
|
599
654
|
- **Why:** The host/MCP path could not run the atomic preflight engine (missing facts, incomplete setup, or unsupported mode).
|
|
600
655
|
- **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.
|
|
601
656
|
|
|
657
|
+
<a id="WRITE_GATE_UNAVAILABLE"></a>
|
|
658
|
+
|
|
659
|
+
### `WRITE_GATE_UNAVAILABLE`
|
|
660
|
+
|
|
661
|
+
**Write gate could not run**
|
|
662
|
+
|
|
663
|
+
- **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.
|
|
664
|
+
- **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.
|
|
665
|
+
|
|
602
666
|
<a id="DESIGN_SMELL_REGRESSION"></a>
|
|
603
667
|
|
|
604
668
|
### `DESIGN_SMELL_REGRESSION`
|
|
@@ -626,7 +690,7 @@ Haken slaving: few slow keys (ξ) determine derived fast state. Field ingest nev
|
|
|
626
690
|
**Lexical evidence incomplete**
|
|
627
691
|
|
|
628
692
|
- **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.
|
|
629
|
-
- **Fix:**
|
|
693
|
+
- **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.
|
|
630
694
|
|
|
631
695
|
<a id="ANALYSIS_COVERS_NO_FILES"></a>
|
|
632
696
|
|
|
@@ -904,6 +968,51 @@ never opting out of knowing.
|
|
|
904
968
|
- **Why:** `sliceIdentity` is `stars` and two different `sliceFolders` prefixes bind as the same slice id. Parallel trees of one feature do that on purpose; unrelated trees that share the last folder name merge by accident. The warning names both paths.
|
|
905
969
|
- **Fix:** Keep `stars` when those prefixes are one feature. Otherwise use `path`, or rename the last literal so the prefixes do not bind as the same id. Advisory — it does not fail the check.
|
|
906
970
|
|
|
971
|
+
<a id="CONFIG_CHILD_SLICES_VERSION"></a>
|
|
972
|
+
|
|
973
|
+
### `CONFIG_CHILD_SLICES_VERSION`
|
|
974
|
+
|
|
975
|
+
**Config needs a newer arkgate than a pinned copy**
|
|
976
|
+
|
|
977
|
+
- **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.
|
|
978
|
+
- **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.
|
|
979
|
+
|
|
980
|
+
<a id="CONFIG_CHILD_SLICE_EXTENDS"></a>
|
|
981
|
+
|
|
982
|
+
### `CONFIG_CHILD_SLICE_EXTENDS`
|
|
983
|
+
|
|
984
|
+
**Child slice id does not extend its universe**
|
|
985
|
+
|
|
986
|
+
- **Why:** A path resolved a child id that is not the universe id plus a further segment. The child wall does not treat that id as a child, so the edge is universe common until the folders line up.
|
|
987
|
+
- **Fix:** Point childSlices.sliceFolders at children under the same universe id the outer sliceFolders already names. Doctor names the path. Advisory — it does not fail the check.
|
|
988
|
+
|
|
989
|
+
<a id="CONFIG_CHILD_SLICE_CROSS_UNIVERSE"></a>
|
|
990
|
+
|
|
991
|
+
### `CONFIG_CHILD_SLICE_CROSS_UNIVERSE`
|
|
992
|
+
|
|
993
|
+
**Child slice allowance cannot cross the universe wall**
|
|
994
|
+
|
|
995
|
+
- **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.
|
|
996
|
+
- **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.
|
|
997
|
+
|
|
998
|
+
<a id="CONFIG_CHILD_SLICES_INERT"></a>
|
|
999
|
+
|
|
1000
|
+
### `CONFIG_CHILD_SLICES_INERT`
|
|
1001
|
+
|
|
1002
|
+
**childSlices on a rule that cannot run it**
|
|
1003
|
+
|
|
1004
|
+
- **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).
|
|
1005
|
+
- **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.
|
|
1006
|
+
|
|
1007
|
+
<a id="CONFIG_SLICE_LEGACY_STARS_ID"></a>
|
|
1008
|
+
|
|
1009
|
+
### `CONFIG_SLICE_LEGACY_STARS_ID`
|
|
1010
|
+
|
|
1011
|
+
**Slice id written in the 4.8.23 stars form**
|
|
1012
|
+
|
|
1013
|
+
- **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.
|
|
1014
|
+
- **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.
|
|
1015
|
+
|
|
907
1016
|
## Meta
|
|
908
1017
|
|
|
909
1018
|
<a id="ARK_UNKNOWN"></a>
|
package/docs/package-surface.md
CHANGED
|
@@ -66,25 +66,25 @@ hardening guide remains repository-hosted rather than duplicated in the gate tar
|
|
|
66
66
|
| **Governance weight** | `ark-check --doctor --json` → `doctor.contractHealth.governanceWeight` | Additive, **advisory only** — raw facts (`declaredLayers`, `populatedLayers`, `governedFiles`, `rules`, `deniedEdges`, `allowedEdges`, `filesPerLayer`, `rulesPerLayer`) plus a fixed comparative band `weight: heavy | typical | light | unknown` and its fixed `note`. Fixed deterministic thresholds: **heavy** = fewer than 25 governed files per declared layer AND (6+ layers OR 4+ well-formed rules per layer); **light** = at most 2 layers over 150+ governed files; **unknown** = no layers or no governed files; everything else is **typical** (banding uses raw ratios; the reported ratios are rounded for display). `notAScore: true` is explicit: never a composite score, ranking, or gate input; the heavy note asks to justify NEW layers/rules and never suggests deleting working ones. Human doctor prints a line only for `heavy`/`light`. |
|
|
67
67
|
| **Report parity and snapshot evidence (4.2)** | `ark-check --report` → advisory sections (`data-advisory="contractHealth\|ambientState\|parseHealth\|arkRun"`, nested `governanceWeight`) + layer wall badges; `.ark/reports/*.json` | The report is a rendering of doctor truth. **Standing rule:** every doctor advisory ships with its report section — enforced by the `reportParity` guard, which enumerates the doctor's advisory keys and fails on any missing section. Snapshots add best-effort Git `HEAD`/branch/dirty provenance without a shell; unavailable Git is explicit. Evolution renders the Ark score delta only when both snapshots name the same ArkGate version, while retaining raw facts across versions. Thin `arkRun` on `latest.json` is `notAScore` residual honesty for `ark status`. |
|
|
68
68
|
| **MCP project identity (4.2)** | `ark_identity`; `arkgate/schema/project-identity` or `arkgate/schema/ark.project-identity.schema.json`; root API constants/helpers/types | Schema `1.0`. `projectId` hashes canonical root + config path and stays stable across contract edits/restarts; runtime id/start time are separate. Every project-bound tool result and error carries `projectIdentity`, `binding` (`matched` / `unverified` / `mismatch`), and `authoritative`. Canonical out-of-root config/file evidence fails before project data. |
|
|
69
|
-
| **MCP tools and compatibility resource** | `arkgate-mcp`; `ark_manifest`; `ark_status`; `ark://manifest` | Tool names and primary argument shapes are stable within a major. Every tool accepts additive `project.expectedRoot` / optional `expectedProjectId`. The initial handshake requires the exact project root; a contained descendant is authoritative only together with the matching project id. Legacy tool calls remain callable but `unverified` and non-authoritative. `ark_manifest` is the authoritative contract surface after binding. **`ark_status`** returns the status manifest envelope (parity with `ark status --json`). Standard `resources/read` cannot portably carry the expectation, so `ark://manifest` remains compatibility-only and always unverified/non-authoritative. The server never retargets from input. |
|
|
69
|
+
| **MCP tools and compatibility resource** | `arkgate-mcp`; `ark_manifest`; `ark_status`; `ark://manifest` | Tool names and primary argument shapes are stable within a major. Every tool accepts additive `project.expectedRoot` / optional `expectedProjectId`. The initial handshake requires the exact project root; a contained descendant is authoritative only together with the matching project id. Legacy tool calls remain callable but `unverified` and non-authoritative. `ark_manifest` is the authoritative contract surface after binding. **`ark_status`** returns the status manifest envelope (parity with `ark status --json`). Standard `resources/read` cannot portably carry the expectation, so `ark://manifest` remains compatibility-only and always unverified/non-authoritative. The server never retargets from input. Every published `outputSchema` has top-level `type: "object"` and the returned `structuredContent` validates against it (MCP SDK clients check both). A contract edit after startup makes project tools return `CONTRACT_STALE` until restart. `arkgate-mcp --help` / `--version` print and exit. |
|
|
70
70
|
| **`ark.config.json`** | Layer globs, optional `layers[].description`, optional `layers[].trustBoundary`, optional `layers[].owners`, optional `requireLayerOwners`, rules, include/exclude, forbiddenGlobals, intent prefixes, `peerIsolation`, `dynamicImportAllowlist`, `safety` thresholds; optional **`coverage`** controls (`testGlobs`, `maxFiles`); optional **`arkRules`** map (schema `1.1+`); optional **`arkRun`** extra (schema `1.2+`); optional **`arkOrder`** extra (schema `1.3+`) | Versioned by `schemaVersion`; unknown fields fail closed and migrations preserve the previous supported major. Absence of `coverage`, `arkRules`, `arkRun`, or `arkOrder` is byte-for-byte silent on Layers / ArkRules verdicts. Enforced extra teeth share the CLI / MCP / hook / preflight / CI verdict and arm only when the layer plane is classified (same ArkRules floor). |
|
|
71
71
|
| **Layer caption (`layers[].description`, 4.8.7)** | Optional string on each layer. Projected onto `ark_place` / prepare-write / MCP place JSON, doctor JSON + human, coverage JSON, and the HTML Purpose column when present. `/ark-adopt` writes it from the product map or glossary; `/ark-place` prints it next to layer name + globs. | Existing optional field — **no `schemaVersion` bump**, no new key, no 14th skill. Copy is **app context** (a product sentence such as `Purchase requests — from asked to received.`), not architecture jargon. Stripped from `policyHash` like `stewards`; caption-only edits are neutral. Absence is silent: never a residual, never a score, never `--strict-config` fail, never flips `valid`. Compact starters may omit. |
|
|
72
72
|
| **Layer trust (`layers[].trustBoundary`)** | Optional closed tag on each layer: `public` \| `auth` \| `admin` \| `internal`. Projected onto `ark_place` / prepare-write / MCP place JSON, doctor JSON + human, coverage JSON, and the HTML report when present. `/ark-adopt` writes it when the product map names that door; `/ark-place` prints `trust: public`. | Additive optional field — **no `schemaVersion` bump**, no new skill. Stripped from `policyHash` like `stewards` and `layers[].description`; tag-only edits are neutral. Absence is silent: never a residual, never a score, never `--strict-config` fail, never flips `valid`. Invalid values fail the schema. Compact starters may omit. Not host/CI TLS. Not an import-rule matrix. |
|
|
73
73
|
| **Layer owners (`layers[].owners` + `requireLayerOwners`)** | Optional GitHub handles or emails on each layer. Projected onto place / prepare-write / MCP / doctor / coverage / HTML when present. `requireLayerOwners: true` asks for owners on every live (non-reserved) layer: doctor names the first missing house, `--strict-config` refuses, and the write gate denies a write into that house. | Additive optional fields — **no `schemaVersion` bump**, no new skill. Owners are stripped from `policyHash` like captions; owner-only edits are neutral. The require flag stays in the hash. Absence of owners is silent unless the require flag is on. Invalid identity (display name) fails the schema. Compact starters may omit. Not import-rule teeth. No `/ark-owners`. |
|
|
74
|
-
| **ArkRules inventory / under-contract (4.0; layer context 4.2)** | `ark-check --rules-inventory [--json]`; doctor `rulesUnderContract`; MCP `ark_rules_inventory` | Additive. Honest counts (inventoried / under-contract / frozen) — **never a score**. When configured layer evidence exists it overrides filename role guesses: a Domain file named `handler` is not a controller candidate. Test/fixture/seed/migration/exclusion surfaces plus narrow development-identity, PostgreSQL OID, and technical I/O constants are silent. Without layer evidence, backward-compatible path/content heuristics remain. Structure/invariant diagnostics use adapter `1.4` provenance. |
|
|
74
|
+
| **ArkRules inventory / under-contract (4.0; layer context 4.2)** | `ark-check --rules-inventory [--json]`; doctor `rulesUnderContract` + `rulesMigration`; MCP `ark_rules_inventory` | Additive. Honest counts (inventoried / under-contract / frozen) — **never a score**. Structure candidates count as under contract by declared (layer, sensor); frozen counts `ARKRULE_*` / `INVARIANT_*` baseline keys. CLI and MCP payloads share one builder (same keys, incl. `coverageEvidence`). When configured layer evidence exists it overrides filename role guesses: a Domain file named `handler` is not a controller candidate. Test/fixture/seed/migration/exclusion surfaces plus narrow development-identity, PostgreSQL OID, and technical I/O constants are silent. Without layer evidence, backward-compatible path/content heuristics remain. Structure/invariant diagnostics use adapter `1.4` provenance. |
|
|
75
75
|
| **`arkgate/schema/project-identity`** or **`arkgate/schema/ark.project-identity.schema.json`** | MCP canonical project, contract, runtime, expectation, and binding envelope | Schema `1.0`. Initial `expectedRoot` must be the exact project root. A contained descendant can match only when `expectedProjectId` is also present and correct; id-only matching stays non-authoritative. Mismatch codes are `PROJECT_ROOT_MISMATCH`, `PROJECT_ID_MISMATCH`, and `INVALID_PROJECT_EXPECTATION`. |
|
|
76
76
|
| **Package pin dual-truth (4.0)** | doctor JSON `packageVersionTruth`; upgrade JSON/human note when pin behind CLI | Additive, advisory. Surfaces after `upgrade --no-install` when managed CLI is ahead of package.json. |
|
|
77
77
|
| **Managed upgrade self-service honesty (4.5 / DF05)** | `ark upgrade [--json]` → `selfService` (+ human “Self-service honesty” lines) | Additive, advisory. Answers without a maintainer: write-path activation labels per selected host (`hard`\|`advisory`\|`unavailable`) and customized content-identity preserve (`customizedPaths` / `customizedContentPreserved`). Soft hosts never hard; upgrade never invents `hardWriteActive` from disk alone. Always `notAScore: true`. Not a gate input; not part of `planDigest`. |
|
|
78
78
|
| **Product honesty readiness split (4.1.1)** | doctor JSON `productHonesty` | Additive. `unfinished` / `headline` / `primaryNextAction` / `reasonIds` remain; EH adds `contractReadiness` (`ready`\|`partial`\|`not-ready`), `localWriteBoundary` (`advisory`\|`hard`\|`unverified`\|`unknown`), `architectureReasonIds`, `environmentResidualIds` / `environmentResiduals`. Soft-write hosts stay in evidence without alone forcing global **Not finished**. `notAScore: true` always. A physical-cohesion residual that reshape decisions have not suppressed adds `physical-cohesion-residual`, which clears `elegant` and `finished` and sets the headline to residual remaining; the gate verdict, `designFitness`, `designWeak`, and `patternBets` stay unchanged. When that residual still proposes `reshapePilot.nextPilot`, `pilotLoop` is active with that one extraction card. |
|
|
79
79
|
| **Policy transition analysis (3.1.0)** | `analyzePolicyDelta(...)`; MCP `ark_policy_delta`; CLI `--policy-base` / `--policy-base-ref` / `--policy-ack`; check JSON `policyDelta` | Additive schema `1.0`. Classifications and finding ids are deterministic. Weakening/judgment requires an acknowledgement bound to both policy hashes and the exact blocking finding set. A new layer or new allow edge is `judgment-required`. On the CLI/MCP policy-ack plane, `adrPath` must name a short note under `docs/adr/` or `docs/decisions/` (`policyDelta.adrNote`). Domain hash match stays I/O-free. |
|
|
80
|
-
| **Team parliament (law vs feature)** | Optional `stewards` on `ark.config.json` (GitHub handle or email); CLI `--local` / `--changed` / `--against` / `--base` / `--contract-diff` / `--contract-session` / `--persona` / `--author`; check JSON `teamParliament`; `ark status --vs`; write-gate mixed-batch deny | Additive. Law files must not mix with product source. Loosen / baseline-grow are steward-only when `stewards` is set. `--against` ratchets vs the base-ref baseline. `--changed` scans touched sources plus their import closure. `--local` (or `ARK_CHECK_LOCAL=1`) is the same cheap path and stays per `--root`; it cannot combine with `--strict-merge`. Check JSON may add `local`, `scope: "changed"`, `analysisRoot`. `stewards`, `layers[].description`, `layers[].trustBoundary`, and `layers[].owners` are excluded from policy hash. `requireLayerOwners` stays in the hash. Identity is handle or email, not git `user.name`. No org plane. |
|
|
80
|
+
| **Team parliament (law vs feature)** | Optional `stewards` on `ark.config.json` (GitHub handle or email); CLI `--local` / `--changed` / `--against` / `--base` / `--contract-diff` / `--contract-session` / `--persona` / `--author`; check JSON `teamParliament`; `ark status --vs`; write-gate mixed-batch deny | Additive. Law files must not mix with product source. Loosen / baseline-grow are steward-only when `stewards` is set. `--against` ratchets vs the base-ref baseline. `--changed` scans touched sources plus their import closure. `--local` (or `ARK_CHECK_LOCAL=1`) is the same cheap path and stays per `--root`; it cannot combine with `--strict-merge` or `--update-baseline`. Changed paths are relative to `--root` (monorepo packages included). A missing base ref or failed git listing is exit 2 (`changed-needs-base` / `local-needs-base` / `contract-diff-needs-base` for `--contract-diff` and `--persona steward` / `changed-paths-unavailable`), never a pass. `--report` applies the committed baseline implicitly except under `--strict` / `--strict-merge` / `--contract-diff` / `--against`. Check JSON may add `local`, `scope: "changed"`, `analysisRoot`. `stewards`, `layers[].description`, `layers[].trustBoundary`, and `layers[].owners` are excluded from policy hash. `requireLayerOwners` stays in the hash. Identity is handle or email, not git `user.name`. No org plane. |
|
|
81
81
|
| **Atomic change preflight (3.1.0)** | `preflightChange(...)`; CLI `ark preflight --changes <file> --json`; MCP `ark_prepare_change` | Additive schema `1.0`. One complete governed production-source `{path,content}` / `{path,delete:true}` batch; read-only; returns operation, content/tree/policy/compiler fingerprints and stable graph findings. MCP availability alone is advisory. |
|
|
82
82
|
| **Architecture change map (3.1.0)** | `arkgate/schema/change-map` or `arkgate/schema/ark.change-map.schema.json`; CLI `ark preflight --change-map <file>`; MCP `ark_prepare_change.changeMap` | Optional strict schema `1.0`. Canonical planned paths + operations + resolved Ark layers + dependencies between planned files. Preflight returns `changeMapHash`; absence is normal and adds no project file. Structural intent only, never behavioral completion. |
|
|
83
83
|
| **Structural convergence (3.1.0)** | `analyzeArchitectureConvergence(...)`; map-enabled `preflightChange(...)`; existing CLI/MCP preflight adapters | Additive `convergence` result with stable `satisfied`, `missing`, `contradictory`, and `unplanned` findings. Uses the supplied/current project tree as base and the explicit complete change set as candidate; no implicit Git or LLM input. `readOnly: true`; `behavioralCompletion: "not-evaluated"`. Structural mismatch makes preflight invalid. |
|
|
84
84
|
| **Enforcement ladder + fixed journey (3.1.0)** | `doctor.writePath.enforcementLadder`; hook repair `enforcement`; `npm run eval:change-integrity` | Additive schema `1.0` separates supported/installed/active/bypassable state and evidence. Hard is operation-scoped only for a supported covered hook; MCP is advisory; required CI status stays unverified locally. Fixed no-context fixture proves CLI/MCP/hook/final parity, one casual denial, acceptance behavior, and strict Ark. |
|
|
85
85
|
| **Enforcement state** | `doctor.writePath.enforcementState`; schema/type | Schema `1.1`: runtime observation, operation coverage, and operation-scoped `hard`. Only fresh covered active-host evidence permits `hard:true`; unverified assets and MCP remain non-hard. |
|
|
86
86
|
| **Design delta** | `--strict-merge` / `--strict` (created paths when a Git base exists); `--fail-on-new-smells --base-ref <ref>` (full ratchet); hook/MCP; schema/types | Schema `1.0`: identities, touched paths, optional `enforcementScope`. Default merge blocks **created** `domain-logic-in-ui` files vs merge-base; missing base skips (does not exit 2). Full new+worsened on touched paths remains opt-in `--fail-on-new-smells` (missing base fails closed). Historical residual and worsened-in-existing-file stay green on `--strict-merge`. Global doctor smells stay advisory. |
|
|
87
|
-
| **`arkgate/schema/analysis-result`** or **`arkgate/schema/ark.analysis-result.schema.json`** | Public CLI/MCP/hook diagnostic envelope (`schemaVersion`, `mode`, `valid`, `completeness`, `completenessReasons`, `diagnostics`, resolved identities) | Schema **`1.5`** adds optional stable finding refs on diagnostics: `findingRef` (`fnv1a-` + hex), `targetKey` (baseline-compatible freeze identity), `docsCodePath` (`docs/diagnostics.md#RULE_ID`). Factory-emitted diagnostics always include them; consumer-owned 1.0–1.4 values remain valid without them. `1.4` added optional `evidence.arkruleId` / `evidence.arkruleSource` for ArkRules; `1.3` distinguished `resolved-candidate-facts` from `lexical-compatibility`; partial/unavailable analysis is always non-green, and resolved complete/partial results require policy/resolver/facts/tree identities. `1.2` added completeness and remains accepted alongside consumer-owned 1.0/1.1 values. |
|
|
87
|
+
| **`arkgate/schema/analysis-result`** or **`arkgate/schema/ark.analysis-result.schema.json`** | Public CLI/MCP/hook diagnostic envelope (`schemaVersion`, `mode`, `valid`, `completeness`, `completenessReasons`, `diagnostics`, resolved identities) | Schema **`1.5`** adds optional stable finding refs on diagnostics: `findingRef` (`fnv1a-` + hex), `targetKey` (baseline-compatible freeze identity), `docsCodePath` (`docs/diagnostics.md#RULE_ID`). Factory-emitted diagnostics always include them; consumer-owned 1.0–1.4 values remain valid without them. Optional `evidence.reasonId` (`CROSS_PARENT_SLICE` / `CROSS_SIBLING_SLICE` / `CROSS_PARENT_VIA_SHARED`) with `evidence.universeFrom` / `universeTo` is additive within `1.5` and outside the baseline key. `1.4` added optional `evidence.arkruleId` / `evidence.arkruleSource` for ArkRules; `1.3` distinguished `resolved-candidate-facts` from `lexical-compatibility`; partial/unavailable analysis is always non-green, and resolved complete/partial results require policy/resolver/facts/tree identities. `1.2` added completeness and remains accepted alongside consumer-owned 1.0/1.1 values. |
|
|
88
88
|
| **Stable finding refs (4.3)** | Root API `adapterFindingTargetKey` / `adapterFindingRefFromTargetKey` / `toAdapterDiagnostic` / `createAdapterResult`; CLI/MCP/repair envelopes via analysis-result diagnostics | Multi-turn re-address without fuzzy message match. `targetKey` **is** the baseline (occurrence) key so freeze identity is never orphaned; `findingRef` is a compact FNV-1a of that key. Line/message drift does not change the ref. Multi-turn fixture: `tests/fixtures/finding-refs/multi-turn-stability.json`. |
|
|
89
89
|
| **Diagnostic code catalog** | Root API `DIAGNOSTIC_CATALOG` / `getDiagnosticCatalogEntry` / `diagnosticDocsPath`; docs [diagnostics.md](diagnostics.md) (`#RULE_ID` anchors) | Closed vocabulary of public `ruleId`s with why/fix anchors. Cataloguing only — no new rule semantics. Remediation parity is test-guarded. ArkRun `ARKRUN_*` codes (RN05) share dual-depth `nextAction` / `enthusiastHint`; declaration-list adds are mechanical-safe only when the call-site literal already exists. Docs ship in the npm tarball. |
|
|
90
90
|
| **Status manifest** | CLI `ark status [--json] [--vs <ref>]`; MCP `ark_status`; `arkgate/schema/status-manifest`; root API `buildStatusManifest` / `ARK_STATUS_MANIFEST_SCHEMA` / `projectStatusImprovementCompass` | Schema `1.0`. One session/project snapshot: identity binding, honest write-path activation (`hard`\|`advisory`\|`unavailable`), last-check summary, rules residual counts, primary next action, **`improvementCompass`** with honesty **`mode`** `full`\|`subset`\|`unavailable` (residual ids only; always `notAScore: true`; optional `reasonCode`/`reason`/`factsSource`/`contractHash`), optional **`vsBase`** (pin / contract / baseline grow vs a git ref; advisory only), and additive **`arkRun`** (`notAScore`; `present` / `mode` / `extraMergeTeeth` / residual count — null residual is unknown, not green). **Not a score.** Residual never changes gate verdicts. Never prompts (`CI=1` forces JSON). Optional `--expected-root` / `--expected-project-id` (MCP `project`) for matched vs stale identity. |
|
|
@@ -94,7 +94,7 @@ hardening guide remains repository-hosted rather than duplicated in the gate tar
|
|
|
94
94
|
| **`arkgate/schema/resolved-candidate-facts`** or **`arkgate/schema/ark.resolved-candidate-facts.schema.json`** | Versioned parity-capable input for `analyzeResolvedProject` / `preflightResolvedChange` | Schema `1.2` is additive: optional `classShapes` (1.1) plus ArkRun `arkRunKernelCalls` / `arkRunManagedNews` / `arkRunCompositionRootHits` / `arkRunDeclarations` (RN03–RN04) and ArkOrder `arkOrderPlaneCalls` / `arkOrderGenericUpdates` / `arkOrderRootHits` (OR05). `1.0`/`1.1` payloads remain loadable. Tooling owns filesystem/compiler resolution; Domain/Kernel validate and evaluate supplied facts without importing those effects. Facts name resolver/compiler inputs, governed files, dependency evidence, completeness reasons, candidate tree/facts hashes, and (when present) ArkRun/ArkOrder call-site evidence. Tier-1 sensors emit `ARKRUN_*` / `ARKORDER_*` diagnostics from those facts: advisory never flips `valid`; enforced blocks. Extra absence is silent. |
|
|
95
95
|
| **Config JSON Schema** | `arkgate/schema` or `arkgate/schema/ark.config.schema.json` | Stable package resource subpaths for editor completion and contract tooling. |
|
|
96
96
|
| **Agent skills** | `/ark-*` templates; install via `--install-agent-gates` (often `--skills-only` on top of compact) **or** Agent Skills ecosystem path | **Day zero** is the compact router from `ark start` / `start --apply` + doctor — not the full skill pack. Closed catalog (`ARK_SKILL_NAMES`): first-class doors (including `/ark-order`) plus one-release stubs. Guided expert path remains `/ark-autopilot` after pack install. **4.0:** first-class doors except experimental `/ark-runtime` / `/ark-order` integrate **layers + ArkRules** and must label residual `[Layer]` vs `[ArkRules]`. **4.2:** repo catalogs are content-idempotent; the optional shared Codex home catalog is monotonic across 4.2.0+ installers. Pre-4.2 writers are outside that protocol and must be upgraded first. A durable pending-catalog journal preserves the floor across an interrupted install and is cleared only by its owning same/newer recovery. **4.3:** Agent Skills–compatible layout at `templates/agent-skills/<name>/SKILL.md` (1:1 with flat `templates/skills/*.md`); install via `npx skills add ./node_modules/arkgate/templates/agent-skills` (or the GitHub tree). **#216:** first-class `/ark-order`; ACS05 freeze opened (ADR 0036). Domain `ARK_SKILL_NAMES` + `validateAgentSkillsPackage` + `validateSkillProductCapacity`; drift `npm run check:agent-skills` (layout **and** 100% product coverage). Skills never enforce. |
|
|
97
|
-
| **ESLint subpath** | `arkgate/eslint` | Config-driven layer/import/purity rules plus ArkRun import/`new` envelope (`ark/no-arkrun-kernel-in-domain`, `ark/no-arkrun-direct-new`, `ark/no-arkrun-transport-bypass`) when `arkRun` is on,
|
|
97
|
+
| **ESLint subpath** | `arkgate/eslint` | Config-driven layer/import/purity rules plus ArkRun import/`new` envelope (`ark/no-arkrun-kernel-in-domain`, `ark/no-arkrun-direct-new`, `ark/no-arkrun-transport-bypass`) when `arkRun` is on, ArkOrder envelope (`ark/no-arkorder-kernel-in-domain`, `ark/no-arkorder-generic-update`) when `arkOrder` is on, and ArkRules structure sensors (`ark/arkrules-structure`) when `arkRules` is on; loads consumer `ark.config.json`. Non-blocking findings (ark-check warnings) report on the warn-level `ark/architecture-advisory` (when that rule is not enabled they fall back to the blocking rule id, tagged advisory). `require('arkgate/eslint')` and the ESM default are the same plugin object (`meta`, `rules`, `configs`). Absence of an extra is silent. Missing-root / missing-plane, undeclared-*, and ArkRules invariant coverage stay CLI/MCP. |
|
|
98
98
|
| **GitHub Action** | `pedroknigge/arkgate` (see `action.yml`) | The `uses:` tag/SHA selects the checker source; `version` remains an optional exact npm compatibility override. |
|
|
99
99
|
| **Package metadata** | `arkgate/package.json` | Stable resource subpath for tooling that needs the installed manifest. |
|
|
100
100
|
|
|
@@ -141,6 +141,8 @@ are grouped below.
|
|
|
141
141
|
| Design delta contract | `ARK_DESIGN_DELTA_SCHEMA_VERSION` |
|
|
142
142
|
| Analysis IR + resolved facts | `ANALYSIS_IR_SCHEMA_VERSION`, `RESOLVED_CANDIDATE_FACTS_SCHEMA_VERSION`, `RESOLVED_CANDIDATE_FACTS_SCHEMA`, `createResolvedCandidateFacts`, `loadResolvedCandidateFacts`, `resolvedFactsEvidenceRequirementsHash`, `deterministicHash`, `stableSerialize` |
|
|
143
143
|
| Config contract | `ARK_CONFIG_SCHEMA`, `ARK_CONFIG_SCHEMA_VERSION`, `loadArkConfigContract`, `parseArkConfigJson` |
|
|
144
|
+
| ArkRules contract | `ARK_RULES_SCHEMA`, `ARK_RULES_SCHEMA_VERSION`, `ARK_RULE_SENSORS`, `ArkRulesValidationError`, `buildEffectiveArkRules`, `emptyEffectiveArkRules`, `loadArkRulesContract`, `parseArkRulesJson` (`parseArkRulesJson` / `loadArkRulesContract` throw `ArkRulesValidationError` with `.issues: ArkRulesIssue[]`) |
|
|
145
|
+
| Effective contract | `EffectiveContractError`, `effectiveContractPolicyPayload`, `resolveEffectiveContract` |
|
|
144
146
|
|
|
145
147
|
The type-only root exports are also semver-supported:
|
|
146
148
|
|
|
@@ -178,6 +180,7 @@ The type-only root exports are also semver-supported:
|
|
|
178
180
|
`AnalysisFile`, `AnalysisImportEdge`, `AnalysisCapabilityUse`, `AnalysisEvidence`,
|
|
179
181
|
`AnalysisViolation`, `AnalysisIr`.
|
|
180
182
|
- Config contract: `ArkConfig`, `ArkConfigLoadResult`.
|
|
183
|
+
- ArkRules contract: `ArkRulesFile`, `ArkRulesIssue`, `EffectiveArkRules`.
|
|
181
184
|
|
|
182
185
|
Runtime-kernel factories, `CAPABILITY_IDS`, `collectCapabilityUses`, and Domain capability mapping
|
|
183
186
|
helpers are deliberately absent from this root. Use `arkgate/runtime` for the
|
|
@@ -195,9 +198,9 @@ claims. Static architecture enforcement does not depend on them.
|
|
|
195
198
|
|
|
196
199
|
| Surface | Import path | Notes |
|
|
197
200
|
|---------|-------------|--------|
|
|
198
|
-
| **ArkRun kernel** | **`arkgate/runtime`** | Public brand **ArkRun**. Same npm package `arkgate` (ADR 0031). Factory `createStrictArkKernel` (each call is an isolated instance; no process-wide `getKernel()` singleton). Root export does **not** include the factory. Optional extra `arkRun` on schema `1.2+`. Event bus, intents, policies, sagas, event buffer, projections, and strict helpers. Managed components declare `uses` / `reactsTo` / `raises` / `sends` on `register()`; `getDependencyInformationPackage()` is a JSON snapshot of ids, lifetime, and declarations and never includes factories, live instances, or input DTOs (ADR 0023). `requestGraph()` slices that snapshot into **process** or **technical** graphs with optional `nodeIds`, `degreesOfSeparation`, and include/exclude query; `formatArkRunGraphMermaid()` (also `graph.mermaid`) is a helper string, never a score. `send()` is the transport port (local / localBlocking / broker); missing broker falls back to in-process local delivery, `ephemeral` defaults true, and **no cloud SDKs ship** in the package (ADR 0024). Opt-in `startInspector()` / `startArkRunInspector()` binds **`127.0.0.1` only**, refuses `NODE_ENV=production`, lazy-loads HTTP, and serves JSON snapshots, SSE, `/graph` slices of the information package, plus queue monitors **`GET /outbox`** and **`GET /workflows`** (full counts + sanitized samples capped at 32; no full event payloads; missing ports are unavailable; no public / authless bind). Snapshot `hardening.durability` classifies the explicit outbox/audit/workflow store ports; default `InMemory*` stores stay visibly `memory`, never durable. Dual bins **`ark-dashboard`** / **`arkgate-dashboard`** poll those JSON facts (ANSI TUI in `bin/` only — presentation is not in the kernel); `ark dashboard` / `arkgate dashboard` dispatch to the same executable. **Shadow / replay / compare** (`shadowInformationPackage`, `compareInformationPackages`, `replayInformationPackages`) are in-memory helpers on that snapshot — not durable, not a second bus (ADR 0033). **Decision tape** `decisionTape` `{ xiHash, event, residual }` via `appendDecisionTape` (ADR 0034). Built-in stores are **InMemory reference only
|
|
199
|
-
| **NestJS adapter** | **`arkgate/nestjs`** | Experimental optional peer `@nestjs/common` for the ArkRun kernel. Same npm package. `@arkgate/runtime/nestjs` is deprecated. |
|
|
200
|
-
| **ArkOrder plane** | **`arkgate/order`** | Public brand **ArkOrder**. Same npm package `arkgate` (ADR 0030) — not `@arkgate/order`. Factory `createOrderPlane`. Valved verbs: `release` / `project` / `ingest` / `proposeRelease` / `apply` / `refreshSigma` / `restore`. No `update`. First freeze is `release()`; later ξ change is `apply` (`ARKORDER_UNVALVED_RELEASE`). `restore(release)`
|
|
201
|
+
| **ArkRun kernel** | **`arkgate/runtime`** | Public brand **ArkRun**. Same npm package `arkgate` (ADR 0031). Factory `createStrictArkKernel` (each call is an isolated instance; no process-wide `getKernel()` singleton). Root export does **not** include the factory. Optional extra `arkRun` on schema `1.2+`. Event bus, intents, policies, sagas, event buffer, projections, and strict helpers. Managed components declare `uses` / `reactsTo` / `raises` / `sends` on `register()`; `getDependencyInformationPackage()` is a JSON snapshot of ids, lifetime, and declarations and never includes factories, live instances, or input DTOs (ADR 0023). `requestGraph()` slices that snapshot into **process** or **technical** graphs with optional `nodeIds`, `degreesOfSeparation`, and include/exclude query; `formatArkRunGraphMermaid()` (also `graph.mermaid`) is a helper string, never a score. `send()` is the transport port (local / localBlocking / broker); missing broker falls back to in-process local delivery, `ephemeral` defaults true, and **no cloud SDKs ship** in the package (ADR 0024). Opt-in `startInspector()` / `startArkRunInspector()` binds **`127.0.0.1` only**, refuses `NODE_ENV=production`, lazy-loads HTTP, and serves JSON snapshots, SSE, `/graph` slices of the information package, plus queue monitors **`GET /outbox`** and **`GET /workflows`** (full counts + sanitized samples capped at 32; no full event payloads; missing ports are unavailable; no public / authless bind). Snapshot `hardening.durability` classifies the explicit outbox/audit/workflow store ports; default `InMemory*` stores stay visibly `memory`, never durable. Dual bins **`ark-dashboard`** / **`arkgate-dashboard`** poll those JSON facts (ANSI TUI in `bin/` only — presentation is not in the kernel); `ark dashboard` / `arkgate dashboard` dispatch to the same executable. **Shadow / replay / compare** (`shadowInformationPackage`, `compareInformationPackages`, `replayInformationPackages`) are in-memory helpers on that snapshot — not durable, not a second bus (ADR 0033). **Decision tape** `decisionTape` `{ xiHash, event, residual }` via `appendDecisionTape` (ADR 0034). Built-in stores are **InMemory reference only**; the default event buffer is capped at `maxHistorySize` and settled after local delivery, and broker handoff outcomes (including failures, as `event.handoffFailed`) are recorded. `createStrictArkKernelFromConfig` gives canonical layer names (what `ark init` writes) their built-in intent prefixes; a custom-named deny-rule layer without `intentPrefixes` is recorded as a `layer.observedFlowUnresolvable` audit record, and throws `ArkKernelConfigError` only when `enforceObservedLayerFlow: 'hard'` is passed explicitly. Branding ArkRun is not a production-durability claim. **`@arkgate/runtime` is deprecated** leftover 0.x (`experimental` dist-tag). |
|
|
202
|
+
| **NestJS adapter** | **`arkgate/nestjs`** | Experimental optional peer `@nestjs/common` for the ArkRun kernel. Same npm package. `arkgate/runtime` and `arkgate/nestjs` load **one shared kernel chunk**, so errors thrown by an `ArkModule` kernel pass `instanceof` against the classes exported from `arkgate/runtime`. `ArkModule.forRoot()` / `forRootAsync()` count as an ArkRun composition-root factory; a Domain-role import of `arkgate/nestjs` is `ARKRUN_KERNEL_IN_DOMAIN`. `@arkgate/runtime/nestjs` is deprecated. |
|
|
203
|
+
| **ArkOrder plane** | **`arkgate/order`** | Public brand **ArkOrder**. Same npm package `arkgate` (ADR 0030) — not `@arkgate/order`. Factory `createOrderPlane`. Valved verbs: `release` / `project` / `ingest` / `proposeRelease` / `apply` / `refreshSigma` / `restore`. No `update`. First freeze is `release()`; later ξ change is `apply` (`ARKORDER_UNVALVED_RELEASE`). `apply` rejects a proposal not computed against the current Release (`ARKORDER_STALE_PROPOSAL`). `restore(release)` reinstalls a validated `Release` (frozen or JSON-deserialized; hash remains identity; not durable) onto an empty plane or at the same ξ at the current or next version (no rollback, no jump; a freeze time after the plane clock fails closed); `ReleaseStore.load()` output is validated the same way (hashes are a consistency check, not a signature), and the plane advances only after `save()` returns. `hashOf` / `hashReleasePayload` verify a stored hash without a second freeze. Default Kernel clock is `Date.now()`. Optional `arkOrder.appliesTo` globs; `maxXiKeys` caps one `release()`, not `xiKeys.length`. Haken: few slow keys; ingest residual `absorb | escalate_up | hold` + closed `reasonCode`; empty blast fails closed. Capacity pack as data (`kind` / `sigmaKey` / `payloadKey` / `op`). Factory options (not config keys): `informationBudget.cannotObserve`, `sigmaMaxAgeMs`, `store` (`ReleaseStore` / `createMemoryReleaseStore`), `catalogDigest`. Thin travel: `ingestTravelAction` absorb→`send` / escalate_up human→`raises`. `IngestEscalate.target` includes `human`. Root `arkgate` export does **not** include the factory. Optional extra `arkOrder` on schema `1.3`. In-memory; not durable; does not close K01. Does not replace ArkRun. Runtime half (shadow/replay/compare + `decisionTape` / `appendDecisionTape`) is ArkRun (ADR 0033 / 0034). Billing gallery is git-only: [examples/arkorder-billing](https://github.com/pedroknigge/arkgate/tree/main/examples/arkorder-billing) (not in the npm tarball). Canonical: [ArkOrder](arkorder.md). |
|
|
201
204
|
|
|
202
205
|
---
|
|
203
206
|
|
|
@@ -212,6 +215,26 @@ import { createOrderPlane, hashOf } from 'arkgate/order';
|
|
|
212
215
|
|
|
213
216
|
One install: `npm install arkgate`. `@arkgate/runtime` is deprecated.
|
|
214
217
|
|
|
218
|
+
**Types for ESM and CommonJS consumers.** Every code entry (`arkgate`, `arkgate/eslint`,
|
|
219
|
+
`arkgate/order`, `arkgate/runtime`, `arkgate/nestjs`) maps `import` to `index.js` +
|
|
220
|
+
`index.d.ts` and `require` to `index.cjs` + `index.d.cts`, and the package ships both
|
|
221
|
+
declaration sets. A CommonJS TypeScript project (`.cts`, or `module` / `moduleResolution`
|
|
222
|
+
`node16` without `"type": "module"`, the usual NestJS shape) type-checks `require` /
|
|
223
|
+
`import x = require(...)` against the CJS declarations. `typesVersions` maps the subpaths for
|
|
224
|
+
legacy `moduleResolution: node10`. Through 4.8.23 the tarball dropped `*.d.cts`, so those
|
|
225
|
+
consumers got TS1471 / TS1479 / TS2307 although runtime `require()` worked.
|
|
226
|
+
|
|
227
|
+
### MCP server via npx and the MCP Registry
|
|
228
|
+
|
|
229
|
+
`npx arkgate@<version> <args>` always runs the bin named after the package, `arkgate`. So
|
|
230
|
+
`arkgate mcp [--root <dir>] [--config <path>] [--hook]` starts the same stdio MCP server as
|
|
231
|
+
`arkgate-mcp`, and forwards every flag to it. The MCP Registry descriptor (`server.json`) launches
|
|
232
|
+
`npx arkgate@<version> mcp --root .` with no `--config`, so it starts in a fresh project too
|
|
233
|
+
(the server reads `ark.config.json` when present; an explicit `--config` to a missing file exits
|
|
234
|
+
1). `arkgate arkgate-mcp` and `arkgate ark-mcp` are accepted as well. Registry entries published
|
|
235
|
+
through 4.8.23 pin arkgate versions that have no `mcp` route, so they keep failing until the
|
|
236
|
+
descriptor is republished for a version that has it.
|
|
237
|
+
|
|
215
238
|
---
|
|
216
239
|
|
|
217
240
|
## Installing from git
|
package/docs/product-voice.md
CHANGED
|
@@ -80,7 +80,7 @@ On the seven lane openings — `docs/use.md`, `docs/develop.md`, `docs/README.md
|
|
|
80
80
|
`README.md` is the first-contact module. Its first screen is four beats: what
|
|
81
81
|
(**Contener · Guiar · Ordenar**), why (design the boundary before you implement;
|
|
82
82
|
a green check is **needs a refactor** when leftover mess remains), one command
|
|
83
|
-
(`npx arkgate@4.8.
|
|
83
|
+
(`npx arkgate@4.8.24 start`), and one honest red result (fail-open named; required
|
|
84
84
|
CI is the hard line). The four paragraphs, the not-that line, the host matrix,
|
|
85
85
|
and the release index sit below `## Appendix`. The not-that line does not lead
|
|
86
86
|
the README.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "arkgate",
|
|
3
|
-
"version": "4.8.
|
|
3
|
+
"version": "4.8.24",
|
|
4
4
|
"description": "When the agent writes a bad import, the write doesn’t land. The same check fails the pull request.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -8,29 +8,54 @@
|
|
|
8
8
|
"types": "./dist/index.d.ts",
|
|
9
9
|
"exports": {
|
|
10
10
|
".": {
|
|
11
|
-
"
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./dist/index.d.cts",
|
|
17
|
+
"default": "./dist/index.cjs"
|
|
18
|
+
}
|
|
14
19
|
},
|
|
15
20
|
"./eslint": {
|
|
16
|
-
"
|
|
17
|
-
|
|
18
|
-
|
|
21
|
+
"import": {
|
|
22
|
+
"types": "./dist/eslint/index.d.ts",
|
|
23
|
+
"default": "./dist/eslint/index.js"
|
|
24
|
+
},
|
|
25
|
+
"require": {
|
|
26
|
+
"types": "./dist/eslint/index.d.cts",
|
|
27
|
+
"default": "./dist/eslint/index.cjs"
|
|
28
|
+
}
|
|
19
29
|
},
|
|
20
30
|
"./order": {
|
|
21
|
-
"
|
|
22
|
-
|
|
23
|
-
|
|
31
|
+
"import": {
|
|
32
|
+
"types": "./dist/order/index.d.ts",
|
|
33
|
+
"default": "./dist/order/index.js"
|
|
34
|
+
},
|
|
35
|
+
"require": {
|
|
36
|
+
"types": "./dist/order/index.d.cts",
|
|
37
|
+
"default": "./dist/order/index.cjs"
|
|
38
|
+
}
|
|
24
39
|
},
|
|
25
40
|
"./runtime": {
|
|
26
|
-
"
|
|
27
|
-
|
|
28
|
-
|
|
41
|
+
"import": {
|
|
42
|
+
"types": "./dist/runtime/index.d.ts",
|
|
43
|
+
"default": "./dist/runtime/index.js"
|
|
44
|
+
},
|
|
45
|
+
"require": {
|
|
46
|
+
"types": "./dist/runtime/index.d.cts",
|
|
47
|
+
"default": "./dist/runtime/index.cjs"
|
|
48
|
+
}
|
|
29
49
|
},
|
|
30
50
|
"./nestjs": {
|
|
31
|
-
"
|
|
32
|
-
|
|
33
|
-
|
|
51
|
+
"import": {
|
|
52
|
+
"types": "./dist/nestjs/index.d.ts",
|
|
53
|
+
"default": "./dist/nestjs/index.js"
|
|
54
|
+
},
|
|
55
|
+
"require": {
|
|
56
|
+
"types": "./dist/nestjs/index.d.cts",
|
|
57
|
+
"default": "./dist/nestjs/index.cjs"
|
|
58
|
+
}
|
|
34
59
|
},
|
|
35
60
|
"./schema": "./schemas/ark.config.schema.json",
|
|
36
61
|
"./schema/ark.config.schema.json": "./schemas/ark.config.schema.json",
|
|
@@ -52,6 +77,22 @@
|
|
|
52
77
|
"./schema/ark.status-manifest.schema.json": "./schemas/ark.status-manifest.schema.json",
|
|
53
78
|
"./package.json": "./package.json"
|
|
54
79
|
},
|
|
80
|
+
"typesVersions": {
|
|
81
|
+
"*": {
|
|
82
|
+
"eslint": [
|
|
83
|
+
"./dist/eslint/index.d.ts"
|
|
84
|
+
],
|
|
85
|
+
"order": [
|
|
86
|
+
"./dist/order/index.d.ts"
|
|
87
|
+
],
|
|
88
|
+
"runtime": [
|
|
89
|
+
"./dist/runtime/index.d.ts"
|
|
90
|
+
],
|
|
91
|
+
"nestjs": [
|
|
92
|
+
"./dist/nestjs/index.d.ts"
|
|
93
|
+
]
|
|
94
|
+
}
|
|
95
|
+
},
|
|
55
96
|
"bin": {
|
|
56
97
|
"arkgate": "bin/ark.mjs",
|
|
57
98
|
"arkgate-check": "bin/ark-check.mjs",
|
|
@@ -74,7 +115,6 @@
|
|
|
74
115
|
"!bin/lib/safety-diagnostics.mjs",
|
|
75
116
|
"!bin/lib/ts-resolve.mjs",
|
|
76
117
|
"dist",
|
|
77
|
-
"!dist/**/*.d.cts",
|
|
78
118
|
"schemas",
|
|
79
119
|
"!schemas/*.source.json",
|
|
80
120
|
"docs/README.md",
|
|
@@ -168,7 +208,8 @@
|
|
|
168
208
|
"clean": "rm -rf dist",
|
|
169
209
|
"release:npm": "node scripts/release-npm.mjs",
|
|
170
210
|
"prepublishOnly": "npm run build",
|
|
171
|
-
"bench:hook-path": "node scripts/hook-path-bench.mjs"
|
|
211
|
+
"bench:hook-path": "node scripts/hook-path-bench.mjs",
|
|
212
|
+
"bench:memory": "node scripts/memory-bench.mjs"
|
|
172
213
|
},
|
|
173
214
|
"dependencies": {
|
|
174
215
|
"typescript-ark-host": "npm:typescript@6.0.3"
|