arkgate 4.8.14 → 4.8.16

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.
Files changed (103) hide show
  1. package/CHANGELOG.md +172 -0
  2. package/README.md +17 -7
  3. package/bin/ark-check-runtime.mjs +17 -49
  4. package/bin/ark-mcp-runtime.mjs +111 -2
  5. package/bin/ark-shared.mjs +142 -11
  6. package/bin/ark.mjs +24 -33
  7. package/bin/lib/adr-presence.mjs +97 -0
  8. package/bin/lib/agent-skills-package.mjs +179 -1
  9. package/bin/lib/analysis-completeness.mjs +38 -2
  10. package/bin/lib/analysis-engine.mjs +6 -6
  11. package/bin/lib/architecture-scan.mjs +43 -4
  12. package/bin/lib/ark-run-doctor.mjs +6 -0
  13. package/bin/lib/ark-run-report.mjs +6 -2
  14. package/bin/lib/arkrules-sensors.mjs +81 -0
  15. package/bin/lib/baseline-key.mjs +6 -1
  16. package/bin/lib/check-args.mjs +52 -2
  17. package/bin/lib/config-contract.mjs +65 -2
  18. package/bin/lib/diagnostic-catalog.mjs +5 -1
  19. package/bin/lib/doctor-advisories.mjs +120 -10
  20. package/bin/lib/doctor-green-cite.mjs +139 -0
  21. package/bin/lib/doctor-human.mjs +115 -67
  22. package/bin/lib/doctor-next-actions.mjs +23 -0
  23. package/bin/lib/doctor-plan.mjs +35 -2
  24. package/bin/lib/enforcement-honesty.mjs +47 -2
  25. package/bin/lib/field-install.mjs +47 -7
  26. package/bin/lib/first-run-help.mjs +9 -1
  27. package/bin/lib/host-support-matrix.mjs +9 -1
  28. package/bin/lib/html-report-depth.mjs +2 -0
  29. package/bin/lib/html-report.mjs +13 -2
  30. package/bin/lib/import-resolve.mjs +74 -13
  31. package/bin/lib/improvement-compass-doctor.mjs +8 -1
  32. package/bin/lib/improvement-compass-map.mjs +5 -1
  33. package/bin/lib/invariant-coverage.mjs +121 -0
  34. package/bin/lib/invariant-tests-path.mjs +212 -0
  35. package/bin/lib/layer-description.mjs +90 -8
  36. package/bin/lib/mcp-hook-payload.mjs +56 -0
  37. package/bin/lib/no-domain-frontend.mjs +91 -0
  38. package/bin/lib/package-manager.mjs +8 -0
  39. package/bin/lib/presets.mjs +3 -4
  40. package/bin/lib/product-copy.mjs +15 -0
  41. package/bin/lib/projected-governed-coverage.mjs +114 -0
  42. package/bin/lib/prototype-shortcuts.mjs +224 -0
  43. package/bin/lib/recommend-cli.mjs +54 -0
  44. package/bin/lib/remediation.mjs +15 -0
  45. package/bin/lib/resolved-candidate-facts.mjs +83 -66
  46. package/bin/lib/rules-under-contract.mjs +117 -2
  47. package/bin/lib/snippet-analysis.mjs +14 -8
  48. package/bin/lib/start-preview.mjs +24 -2
  49. package/bin/lib/states-transitions-presence.mjs +212 -0
  50. package/bin/lib/status-command.mjs +2 -0
  51. package/bin/lib/status-transition-catalog.mjs +410 -0
  52. package/bin/lib/team-parliament-io.mjs +10 -0
  53. package/bin/lib/violations.mjs +13 -1
  54. package/bin/lib/write-path-capabilities.mjs +20 -5
  55. package/bin/lib/write-path-detect.mjs +27 -2
  56. package/dist/{configTypes-j7so8B4O.d.ts → configTypes-VD0qcubY.d.ts} +21 -1
  57. package/dist/{diagnosticCatalog-DVx_2RmF.d.ts → diagnosticCatalog-KWvGLI1U.d.ts} +24 -3
  58. package/dist/eslint/index.cjs +4 -4
  59. package/dist/eslint/index.d.ts +1 -1
  60. package/dist/eslint/index.js +4 -4
  61. package/dist/index.cjs +34 -34
  62. package/dist/index.d.ts +71 -10
  63. package/dist/index.js +34 -34
  64. package/dist/nestjs/index.cjs +5 -5
  65. package/dist/nestjs/index.d.ts +3 -3
  66. package/dist/nestjs/index.js +5 -5
  67. package/dist/runtime/index.cjs +15 -15
  68. package/dist/runtime/index.d.ts +6 -6
  69. package/dist/runtime/index.js +15 -15
  70. package/dist/{types-tGhZUiGX.d.ts → types-BSzRy2X1.d.ts} +1 -1
  71. package/dist/{types-Djbs3KjE.d.ts → types-D5GT5ZT8.d.ts} +3 -1
  72. package/docs/README.md +1 -1
  73. package/docs/agent-guide.md +8 -4
  74. package/docs/ai-gates.md +10 -3
  75. package/docs/brownfield-adoption.md +4 -1
  76. package/docs/configuration.md +66 -10
  77. package/docs/develop.md +4 -1
  78. package/docs/diagnostics.md +48 -4
  79. package/docs/enthusiast/how-to-agent-gates.md +5 -0
  80. package/docs/enthusiast/how-to-pick-shape.md +1 -1
  81. package/docs/package-surface.md +7 -5
  82. package/docs/use.md +10 -3
  83. package/package.json +1 -1
  84. package/schemas/ark.config.schema.json +24 -3
  85. package/server.json +2 -2
  86. package/templates/agent-skills/README.md +1 -1
  87. package/templates/agent-skills/ark-adopt/SKILL.md +97 -1
  88. package/templates/agent-skills/ark-autopilot/SKILL.md +12 -3
  89. package/templates/agent-skills/ark-coverage/SKILL.md +2 -2
  90. package/templates/agent-skills/ark-explain/SKILL.md +6 -3
  91. package/templates/agent-skills/ark-explore/SKILL.md +33 -1
  92. package/templates/agent-skills/ark-place/SKILL.md +42 -3
  93. package/templates/agent-skills/ark-runtime/SKILL.md +4 -2
  94. package/templates/agent-skills/ark-upgrade/SKILL.md +1 -1
  95. package/templates/arkrules/DomainModel.json +14 -1
  96. package/templates/skills/ark-adopt.md +97 -1
  97. package/templates/skills/ark-autopilot.md +12 -3
  98. package/templates/skills/ark-coverage.md +2 -2
  99. package/templates/skills/ark-explain.md +6 -3
  100. package/templates/skills/ark-explore.md +33 -1
  101. package/templates/skills/ark-place.md +42 -3
  102. package/templates/skills/ark-runtime.md +4 -2
  103. package/templates/skills/ark-upgrade.md +1 -1
@@ -1,4 +1,4 @@
1
- import { i as Policy, P as PolicyViolation, I as IntentName, j as IntentCreator, k as IntentRelationship, b as ArchitectureProfile, D as DomainEvent, E as EventMetadata, h as PolicyEnforcementMode, A as ArchitectureLayer, c as ArchitectureRule, d as ArkCheckConfig } from './types-Djbs3KjE.js';
1
+ import { i as Policy, P as PolicyViolation, I as IntentName, j as IntentCreator, k as IntentRelationship, b as ArchitectureProfile, D as DomainEvent, E as EventMetadata, h as PolicyEnforcementMode, A as ArchitectureLayer, c as ArchitectureRule, d as ArkCheckConfig } from './types-D5GT5ZT8.js';
2
2
 
3
3
  /**
4
4
  * PolicyEngine
@@ -1,4 +1,4 @@
1
- import { a as ArkConfigRule, f as ArkConfigLayer, A as ArkConfig } from './configTypes-j7so8B4O.js';
1
+ import { a as ArkConfigRule, f as ArkConfigLayer, A as ArkConfig } from './configTypes-VD0qcubY.js';
2
2
 
3
3
  /**
4
4
  * Policy types for the Ark kernel.
@@ -145,6 +145,8 @@ interface ArchitectureLayer {
145
145
  */
146
146
  match?: (name: string) => boolean;
147
147
  description?: string;
148
+ trustBoundary?: 'public' | 'auth' | 'admin' | 'internal';
149
+ owners?: string[];
148
150
  order?: number;
149
151
  }
150
152
  type ArchitectureRule = ArkConfigRule;
package/docs/README.md CHANGED
@@ -73,7 +73,7 @@ These are **not** the day-to-day product path. They stay in the repo for evidenc
73
73
  | Field adoption kit (scaffolding, not closed) | [field/](field/) |
74
74
  | Runtime hardening (experimental) | [production-hardening.md](production-hardening.md) |
75
75
 
76
- Prepared: [CHANGELOG](../CHANGELOG.md) (`arkgate@4.8.14`; not published until `publish-npm` for `v4.8.14`).
76
+ Prepared: [CHANGELOG](../CHANGELOG.md) (`arkgate@4.8.16`; not published until `publish-npm` for `v4.8.16`).
77
77
  Current published: [releases/4.8.11.md](releases/4.8.11.md) (`arkgate@4.8.11` on npm `latest`; does not close `K01`).
78
78
  Prior published: [releases/4.8.10.md](releases/4.8.10.md) (`arkgate@4.8.10`).
79
79
  Prior published: [releases/4.8.9.md](releases/4.8.9.md) (`arkgate@4.8.9`).
@@ -46,7 +46,8 @@ ark start → ark start --apply → ark-check --doctor
46
46
 
47
47
  `arkgate-check --doctor` shows what's wrong and what to do first. From **4.0.0**, doctor may
48
48
  also report **`rulesUnderContract`** (ArkRules counts) and **`packageVersionTruth`** when the
49
- CLI is ahead of the package.json pin. The compact router from `ark start` is enough for normal
49
+ CLI is ahead of the package.json pin. Compact doctor names ArkRules only when the
50
+ `arkRules` map is on — absence stays silent. The compact router from `ark start` is enough for normal
50
51
  feature work. Full `/ark-*` skills are **expert depth** and label residual **`[Layer]`** vs
51
52
  **`[ArkRules]`** (except experimental `/ark-runtime`):
52
53
 
@@ -119,6 +120,8 @@ npx ark report --submit --i-confirm-submit
119
120
 
120
121
  `--doctor --json` is a stable envelope (4.6.5+): `{ "schemaVersion": "1.0", "envelope": "doctor", "ok": boolean, "doctor": { … } }`.
121
122
  Payload lives only under `doctor`. Do not parse sibling root keys as the doctor object.
123
+ A green or Healthy line names a file, config key, or test so a stranger can
124
+ check it in about a minute. Uncited green is not honest — treat it as unfinished.
122
125
 
123
126
  Doctor also writes `.ark/ci-merge-boundary.json` (hook configured-not-fired, per-host writePath,
124
127
  CI present-but-not-required, GitHub Free cannot require). Read that file — do not grep `node_modules`.
@@ -279,7 +282,7 @@ npx ark-check --recommend --json
279
282
  `--recommend` does not require `ark.config.json`. It exits `0` and prints a progressive
280
283
  adoption plan: archetype id, preset, `confidence`, `runnerUp`, `why` (shape signals),
281
284
  structured positive/negative `evidence`, discovered `signals.packageUnits`,
282
- `adoptInOrder.phase1`, `firstCommand` (`ark init --archetype …`), and `checkCommand`.
285
+ `adoptInOrder.phase1`, `firstCommand` (`ark start --apply --archetype …`), and `checkCommand`.
283
286
  When the top two shapes are close or projected governed coverage is below 90%, JSON sets
284
287
  `requiresConfirmation: true` and explains why in `confirmationReasons`.
285
288
 
@@ -331,7 +334,8 @@ Filter: **Contener · Guiar · Ordenar** — contain the write, guide the next s
331
334
 
332
335
  **Team parliament:** adopt is a **contract session** (law-only). Feature work must not edit
333
336
  `ark.config.json` / `arkrules/*` / `.ark-baseline.json`. Prefer
334
- `ark-check --changed --base <merge-ref>` in local gates. `--contract-diff` + `--author`
337
+ `ark-check --local --base <merge-ref>` (or `--changed --base`) in local gates.
338
+ `--strict-merge` stays the CI merge line. `--contract-diff` + `--author`
335
339
  when `stewards` is set (`--author` is a GitHub handle or email, not git `user.name`).
336
340
  `ark status --vs <ref>` prints pin / contract / baseline drift.
337
341
 
@@ -883,7 +887,7 @@ Filter: **Contener · Guiar · Ordenar** — contain the write, guide the next s
883
887
  **Canonical authoring source:** flat `templates/skills/<name>.md` (Ark install reads these).
884
888
 
885
889
  **Agent Skills package root** (generated, 1:1 content): `templates/agent-skills/<name>/SKILL.md`
886
- — ships in the npm tarball under `templates/`. Drift guard: `npm run check:agent-skills`.
890
+ — ships in the npm tarball under `templates/`. Drift guard: `npm run check:agent-skills` (layout 1:1 **and** 100% product coverage).
887
891
 
888
892
  ```bash
889
893
  # Ark — expert skill pack (preferred when you also want gates)
package/docs/ai-gates.md CHANGED
@@ -28,7 +28,7 @@ overview: [develop.md](develop.md) · hub: [README.md](README.md).
28
28
  | **Claude Code** | Hard PreToolUse for listed ops when installed + trusted + (for `hard:true`) runtime-observed | Required `arkgate-check --strict-merge` status |
29
29
  | **Grok Build** | Hard PreToolUse for listed ops when installed + trusted + (for `hard:true`) runtime-observed | Required `arkgate-check --strict-merge` status |
30
30
  | **Google Antigravity** | Hard PreToolUse for listed write tools when installed + trusted + (for `hard:true`) runtime-observed | Required `arkgate-check --strict-merge` status |
31
- | **Cursor** | Hard preToolUse for Write/StrReplace when installed + trusted + runtime-observed | Required CI status (same check) |
31
+ | **Cursor** | Hard preToolUse for Write/StrReplace when installed + trusted + `failClosed` + runtime-observed | Required CI status (same check) |
32
32
  | **OpenAI Codex** | Hard PreToolUse for complete local `apply_patch` in CLI/Desktop when installed + trusted + runtime-observed | Required CI status (same check) |
33
33
  | **OpenCode** | **Advisory / best-effort** (MCP + optional experimental plugin) — **not** a hard boundary | Required CI status (same check) |
34
34
 
@@ -126,6 +126,11 @@ violations relative to the file's current on-disk state, so files with pre-exist
126
126
  (baselined) violations stay editable — they just can't get worse. New files block on
127
127
  every violation.
128
128
 
129
+ The hook classifies import targets with the same `layerForRelativePath` specificity as
130
+ `ark-check` (an explicit file pattern beats a broader glob such as `src/lib/**`).
131
+ `LEXICAL_EVIDENCE_INCOMPLETE` means the single-file check is provisional — `ark-check`
132
+ on the tree is the authority. Do not move files solely because the hook named a layer.
133
+
129
134
  ### Opt-in resident hook pilot (Z07)
130
135
 
131
136
  Set `ARK_RESIDENT_HOOK=1` on both `ark-mcp` and its hook command. The pilot reuses the
@@ -329,8 +334,10 @@ Cursor supports MCP servers (`.cursor/mcp.json`) and project hooks (`.cursor/hoo
329
334
  }
330
335
  ```
331
336
 
332
- When that hook is installed and trusted, Cursor **hard-blocks** agent `Write` / `StrReplace`
333
- for governed TypeScript sources (exit 2 or `permission: "deny"`). Repair envelopes may emit;
337
+ When that hook is installed and trusted **and** `failClosed` is `true`, Cursor **hard-blocks**
338
+ agent `Write` / `StrReplace` for governed TypeScript sources (exit 2 or `permission: "deny"`).
339
+ A hook without `failClosed` is fail-open: if the checker cannot run, the write still lands
340
+ (same idea as a file permission — no checker, no write). Repair envelopes may emit;
334
341
  Cursor does **not** guarantee Write `updated_input` reinjection — the agent must fix and retry
335
342
  from `agent_message`. Shell, Tab, and human edits still rely on CI.
336
343
 
@@ -48,7 +48,10 @@ regenerate it unasked.
48
48
 
49
49
  Without this split, broad `**/app/**` Presentation patterns push every API handler into UI and
50
50
  create a Presentation→Persistence tsunami. Specificity still wins: more-specific Application
51
- globs beat Presentation. Adopt writes `.ark/golden-pattern.json` (load-bearing for `/ark-place`).
51
+ globs beat Presentation. **Captions** (what doctor prints next to the layer name) mention Next
52
+ App Router / Pages API / `app/api` only when Next is actually present — a library
53
+ `packages/*` monorepo keeps library-native language. Adopt writes `.ark/golden-pattern.json`
54
+ (load-bearing for `/ark-place`).
52
55
  `ark_place` requires `filePath` (fail-closed — never invents `components/*.tsx` or defaults to Presentation).
53
56
  ArkRules stay **opt-in** (not forced on by start/adopt).
54
57
 
@@ -9,7 +9,7 @@ The CLI, MCP server, and ESLint plugin all use the same parser, migration, defau
9
9
 
10
10
  ```json
11
11
  {
12
- "$schema": "https://unpkg.com/arkgate@2/schemas/ark.config.schema.json",
12
+ "$schema": "https://unpkg.com/arkgate@4/schemas/ark.config.schema.json",
13
13
  "schemaVersion": "1.3",
14
14
  "include": ["src"],
15
15
  "layers": [],
@@ -89,7 +89,14 @@ Top-level fields:
89
89
  - **`coverage`** (optional) — invariant-coverage scan controls: `testGlobs` (globs that decide
90
90
  which files count as tests, replacing the built-in `*.test.*` / `tests/` name heuristic),
91
91
  `maxFiles` (evidence file budget, default `400`) and `coverageRoots` (path prefixes where the
92
- project declares its runner actually executes tests). Absence is silent and changes no verdict.
92
+ project declares its runner actually executes tests). Absence is silent unless the tree is
93
+ **adopted** (required CI or `.ark/adoption-stance.json` advisory-only) **and** the catalog
94
+ has domain invariants that want test evidence (`coverage.test` is not `false`) —
95
+ then a missing or empty tests path fails closed
96
+ (`INVARIANT_TESTS_PATH_MISSING`). Either `testGlobs` or `coverageRoots` satisfies the path.
97
+ When any catalogued invariant is **enforced**, `coverage.coverageRoots` is required
98
+ (`INVARIANT_COVERAGE_ROOTS_MISSING`) — `testGlobs` alone is not enough. Silent when no
99
+ invariant is enforced.
93
100
  Unknown keys fail closed. **`maxFiles` also bounds structural-hint preload** for
94
101
  `orchestration-only`, `thin-adapter`, and `writes-via-aggregate` (the hint loader reuses
95
102
  coverage contents when present). There is no separate `arkrules.hintBudget`. When eligible
@@ -117,8 +124,9 @@ Top-level fields:
117
124
  the invariant just as well as one that runs. Declaring `coverageRoots` gives ArkGate a second
118
125
  declaration to compare the first against: when the only covering test falls outside them, it
119
126
  reports `INVARIANT_COVERAGE_OUTSIDE_ROOTS` (advisory) and refuses to promote that invariant to
120
- `enforced`. Declaring nothing keeps the old silence without a declaration there is nothing to
121
- compare, and ArkGate makes no claim about where tests run.
127
+ `enforced`. Declaring nothing stays silent unless any invariant is already enforced then
128
+ missing roots fail closed (`INVARIANT_COVERAGE_ROOTS_MISSING`), because otherwise coverage can
129
+ certify a test the project never declared a runner root for.
122
130
  - **`arkRules`** (optional, schema `1.1+`) — map of layer name → project-relative path to an
123
131
  ArkRules file (e.g. `"DomainModel": "arkrules/DomainModel.json"`). Keys must match a declared
124
132
  layer. Missing/invalid referenced files **fail closed**.
@@ -179,6 +187,45 @@ Layer fields:
179
187
  ```
180
188
 
181
189
  That sentence is product copy. Not “Rich domain model, business rules, and domain events.”
190
+ - **`layers[].trustBoundary`** (optional) — who this folder is for: `public` |
191
+ `auth` | `admin` | `internal`. Anyone, signed-in users, operators, or only
192
+ other code. `/ark-place` prints `trust: public` next to the layer name;
193
+ doctor, coverage, and the HTML report show the same tag. Changing the tag
194
+ does **not** change `policyHash` (same strip as `stewards` and
195
+ `layers[].description`) and does **not** need a weakening ack. Absence is
196
+ silent: never fails `--strict-config`, never invents a doctor residual, never
197
+ flips `valid`. A wrong value (`"trusted"`, empty string) fails the schema.
198
+ Compact starters may omit it. `/ark-adopt` writes it when the product map
199
+ already names that door; it does not invent tags. No `/ark-trust`. This is
200
+ **not** host/CI TLS and does **not** add import-rule teeth.
201
+ - **`layers[].owners`** (optional) — who owns this folder: GitHub handles or
202
+ emails (same identity as `stewards`). `/ark-place` prints `owner: @handle`
203
+ next to the layer name; doctor, coverage, and the HTML report show the same
204
+ names. Changing the list does **not** change `policyHash` and does **not**
205
+ need a weakening ack. Absence is silent unless **`requireLayerOwners`** is
206
+ `true`. A display name (`Pedro Knigge`), empty array, or empty string fails
207
+ the schema. Compact starters may omit it. `/ark-adopt` writes it when the
208
+ product map already names who owns the house; it does not invent people.
209
+ No `/ark-owners`. This is **not** import-rule teeth.
210
+ - **`requireLayerOwners`** (optional) — when `true`, every live (non-reserved)
211
+ layer must name `owners`. Doctor names the first missing house and the next
212
+ step. `--strict-config` / `--strict-merge` refuse. The write gate denies a
213
+ write into an unowned house (same idea as a folder with no name on the door).
214
+ Absence or `false` is silent. This flag **is** policy teeth (it stays in
215
+ `policyHash`). Flip it on after you have named owners incrementally.
216
+
217
+ ```json
218
+ "layers": [
219
+ {
220
+ "name": "Presentation",
221
+ "patterns": ["src/app/**"],
222
+ "description": "Storefront checkout — what shoppers see.",
223
+ "trustBoundary": "public",
224
+ "owners": ["pedroknigge"]
225
+ }
226
+ ]
227
+ ```
228
+
182
229
  - `intentPrefixes`, `forbiddenGlobals`, `mayImportInfrastructure`, `optional`
183
230
  - `reserved` / `allowEmpty` — future houses whose globs match nothing yet. `--strict-config` does not fail; `CONFIG_LAYER_PATTERN_NO_MATCHES` (typo warning) is skipped. A typo warning fires only when the glob is not reserved.
184
231
  - `capabilities: { deny: [...] }` — opt-in effect walls over the seven capability ids
@@ -297,9 +344,12 @@ steps under `plan.typeOnlyGroup` when volume is high.
297
344
 
298
345
  ### Next.js API shell (framework overlay / presets)
299
346
 
300
- When Next is detected (or `ui-surface` / monorepo patterns apply), **`app/api/**` and
301
- `pages/api/**` classify as Application orchestration**, not Presentation. UI routes stay
302
- Presentation. More-specific Application globs win over broad `**/app/**` Presentation patterns.
347
+ When Next is detected, **`app/api/**` and `pages/api/**` classify as Application
348
+ orchestration**, not Presentation. UI routes stay Presentation. More-specific Application
349
+ globs win over broad `**/app/**` Presentation patterns. Reserved `app/api` globs may still
350
+ appear on `ui-surface` / monorepo presets so a later Next route classifies correctly;
351
+ **layer captions** mention Next App Router / Pages API / `app/api` only when Next is
352
+ actually present. Library and package-monorepo start keep library-native captions.
303
353
  See [brownfield adoption](brownfield-adoption.md#nextjs-honesty-default-overlays--ui-surface--monorepo).
304
354
 
305
355
  ### ArkRules dual plane (when `arkRules` is present)
@@ -359,6 +409,9 @@ invariants, and a covered sample when the map is active.
359
409
  a hash-bound policy weakening. Empty `appliesTo: []` fails closed; zero-match globs emit
360
410
  `ARKRULE_SCOPE_EMPTY` (advisory warn / enforced fail). Enforced + proven uncovered →
361
411
  `INVARIANT_UNCOVERED` with `failsStrict` (partial evidence stays honest, never fake-green).
412
+ When `arkRules` is on and a Domain-role layer has code, empty `invariants[]` is doctor residual
413
+ `INVARIANT_CATALOG_EMPTY` (not “done”). Advisory unless a domain structure rule is already
414
+ `enforced` — then `--strict-merge` can refuse. Absence of `arkRules` stays silent.
362
415
 
363
416
  **What they do not do:** prove business semantics end-to-end; replace Layers import edges;
364
417
  make “green” mean elegant Shape. Promoting structure to enforced can force rename-to-pass
@@ -415,7 +468,7 @@ changing either contract changes its hash and invalidates the acknowledgement.
415
468
 
416
469
  Optional `stewards` lists **GitHub handles or emails** who may **loosen** the contract or
417
470
  **grow** the baseline (`pedroknigge` or `pedroknigge@users.noreply.github.com` — not
418
- `Pedro Knigge`). The field is metadata — it does not change the policy hash. `layers[].description` is stripped the same way (caption-only edits do not change `policyHash` and do not need a weakening ack; `contractHash` still fingerprints the raw config). The lock
471
+ `Pedro Knigge`). The field is metadata — it does not change the policy hash. `layers[].description`, `layers[].trustBoundary`, and `layers[].owners` are stripped the same way (caption-only, tag-only, or owner-list edits do not change `policyHash` and do not need a weakening ack; `contractHash` still fingerprints the raw config). `requireLayerOwners` stays in the hash. The lock
419
472
  matches `--author`, then `GITHUB_ACTOR` / `ARK_STEWARD`, then `GIT_AUTHOR_EMAIL`. A
420
473
  noreply GitHub mail and the handle are the same person. Git `user.name` is not identity.
421
474
 
@@ -442,6 +495,7 @@ type than product source:
442
495
 
443
496
  | Check | What it does |
444
497
  |-------|----------------|
498
+ | `ark-check --local --base origin/dev` | Opt-in local / multi-worktree cheap check. Same engine as `--changed`. Refused with `--strict-merge`. `ARK_CHECK_LOCAL=1` is the same unless CI or a full-tree report mode is on. |
445
499
  | `ark-check --changed --base origin/dev` | Layer check on touched sources only. A CSS/i18n PR pays almost nothing. |
446
500
  | `ark-check --against origin/dev` | New violation keys vs **that ref's** baseline (not only HEAD). |
447
501
  | `ark-check --contract-diff --base origin/dev` | Classifies tighten / loosen / reclassify / baseline-grow. |
@@ -450,8 +504,10 @@ type than product source:
450
504
  | `ark status --vs origin/dev` | One line: pin / contract / baseline drift vs that ref. |
451
505
 
452
506
  Write-gate ApplyPatch denies a batch that mixes law files with product source. Humans who
453
- never hit PreToolUse are unchanged. Local `pnpm` gates should call `--changed --base`, not
454
- only full-tree `--strict-merge`.
507
+ never hit PreToolUse are unchanged. Local `pnpm` gates should call `--local --base` or
508
+ `--changed --base`, not only full-tree `--strict-merge`. Write hooks stay on the lexical
509
+ snippet path — they do not run a full-tree check. Analysis is per `--root` (each git
510
+ worktree has its own root); there is no machine-wide analysis lock.
455
511
 
456
512
  `--changed` resolves the touched sources plus their import closure — not the whole
457
513
  include tree. File-local ArkRules sensors (class shape, orchestration-only, thin-adapter,
package/docs/develop.md CHANGED
@@ -37,9 +37,11 @@ ArkGate solves this by shifting the check to the exact moment of writing. By int
37
37
  ```bash
38
38
  npm install -D arkgate typescript
39
39
  npx arkgate start --apply
40
- npx arkgate-check --doctor
40
+ npx --package=arkgate arkgate-check --doctor
41
41
  ```
42
42
 
43
+ `arkgate-check` is a command in the `arkgate` package. After a local install, `npx arkgate-check --doctor` also works.
44
+
43
45
  Make the import-rules check a **required** merge **status context** (GitHub/GitLab/etc.). The CLI
44
46
  command is `arkgate-check --strict-merge` / `ark-check --strict-merge` — the hard boundary is
45
47
  requiring that job’s status, not merely adding a workflow file:
@@ -166,6 +168,7 @@ npx arkgate agents-md --write # embed/refresh projection markers
166
168
  npx arkgate preflight --changes changes.json --json
167
169
  npx arkgate upgrade --json # managed content preview
168
170
  npx arkgate upgrade --apply
171
+ npx arkgate-check --local --base origin/dev
169
172
  npx arkgate-check --changed --base origin/dev
170
173
  npx arkgate-check --against origin/dev
171
174
  npx arkgate status --vs origin/dev
@@ -44,8 +44,11 @@ Link form for agents: `docs/diagnostics.md#RULE_ID` (exact-case HTML anchors bel
44
44
  | [`ARKRULE_INVARIANT`](#ARKRULE_INVARIANT) | arkrules | ArkRule invariant failed |
45
45
  | [`ARKRULE_SCOPE_EMPTY`](#ARKRULE_SCOPE_EMPTY) | arkrules | ArkRule appliesTo matched zero files |
46
46
  | [`ARKRULE_HINT_BUDGET_EXHAUSTED`](#ARKRULE_HINT_BUDGET_EXHAUSTED) | arkrules | Structural-hint budget exhausted |
47
+ | [`INVARIANT_CATALOG_EMPTY`](#INVARIANT_CATALOG_EMPTY) | arkrules | Domain invariant catalog is empty |
47
48
  | [`INVARIANT_UNCOVERED`](#INVARIANT_UNCOVERED) | arkrules | Invariant without coverage evidence |
48
49
  | [`INVARIANT_COVERAGE_OUTSIDE_ROOTS`](#INVARIANT_COVERAGE_OUTSIDE_ROOTS) | arkrules | Covering test outside the declared coverage roots |
50
+ | [`INVARIANT_COVERAGE_ROOTS_MISSING`](#INVARIANT_COVERAGE_ROOTS_MISSING) | arkrules | Coverage roots missing while an invariant is enforced |
51
+ | [`INVARIANT_TESTS_PATH_MISSING`](#INVARIANT_TESTS_PATH_MISSING) | arkrules | Domain-invariant tests path missing under adopted |
49
52
  | [`ARKRUN_MISSING_ROOT`](#ARKRUN_MISSING_ROOT) | arkrun | No kernel factory in composition roots |
50
53
  | [`ARKRUN_KERNEL_IN_DOMAIN`](#ARKRUN_KERNEL_IN_DOMAIN) | arkrun | Domain-role layer imports the kernel |
51
54
  | [`ARKRUN_DIRECT_NEW`](#ARKRUN_DIRECT_NEW) | arkrun | Managed type constructed with new |
@@ -97,6 +100,7 @@ Link form for agents: `docs/diagnostics.md#RULE_ID` (exact-case HTML anchors bel
97
100
  | [`CONFIG_RULE_UNKNOWN_TO_LAYER`](#CONFIG_RULE_UNKNOWN_TO_LAYER) | config | Rule unknown to layer |
98
101
  | [`CONFIG_AMBIGUOUS_LAYERS`](#CONFIG_AMBIGUOUS_LAYERS) | config | Ambiguous layer classification |
99
102
  | [`CONFIG_UNCLASSIFIED_FILES`](#CONFIG_UNCLASSIFIED_FILES) | config | Unclassified included files |
103
+ | [`CONFIG_LAYER_MISSING_OWNER`](#CONFIG_LAYER_MISSING_OWNER) | config | Layer missing owner |
100
104
  | [`ARK_UNKNOWN`](#ARK_UNKNOWN) | meta | Unknown diagnostic |
101
105
 
102
106
  ## Layer and dependency graph
@@ -289,6 +293,15 @@ Link form for agents: `docs/diagnostics.md#RULE_ID` (exact-case HTML anchors bel
289
293
  - **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.
290
294
  - **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.
291
295
 
296
+ <a id="INVARIANT_CATALOG_EMPTY"></a>
297
+
298
+ ### `INVARIANT_CATALOG_EMPTY`
299
+
300
+ **Domain invariant catalog is empty** · often advisory
301
+
302
+ - **Why:** ArkRules is on and a Domain-role layer has code, but `invariants[]` has no phrases the code must preserve. Empty looks like “done” until someone fills the catalog.
303
+ - **Fix:** Add 1–2 short phrases to `invariants[]` in `arkrules/<Domain>.json` (or the mapped file). Starters show the shape. Advisory unless a domain structure rule is already enforced — then `--strict-merge` can refuse. Do not freeze this finding.
304
+
292
305
  <a id="INVARIANT_UNCOVERED"></a>
293
306
 
294
307
  ### `INVARIANT_UNCOVERED`
@@ -307,7 +320,29 @@ Link form for agents: `docs/diagnostics.md#RULE_ID` (exact-case HTML anchors bel
307
320
  - **Why:** The only test naming this invariant sits outside `coverage.coverageRoots` — the places the project declares its runner executes. ArkGate matches declared text and never executes tests, so it cannot tell whether that file is ever run: coverage there is a test that *exists*, not a test that *runs*.
308
321
  - **Fix:** Move the test under a declared coverage root, or add its root to `coverage.coverageRoots` in ark.config.json. Advisory: it never fails strict, but promotion to enforced refuses on it.
309
322
 
310
- Declaring nothing is silent — without `coverage.coverageRoots` there is no second declaration to compare against, and ArkGate makes no claim about where tests run.
323
+ Declaring nothing is silent unless any catalogued invariant is enforced then missing roots fail closed (`INVARIANT_COVERAGE_ROOTS_MISSING`). Without `coverage.coverageRoots` there is no second declaration to compare against, and ArkGate makes no claim about where tests run.
324
+
325
+ <a id="INVARIANT_COVERAGE_ROOTS_MISSING"></a>
326
+
327
+ ### `INVARIANT_COVERAGE_ROOTS_MISSING`
328
+
329
+ **Coverage roots missing while an invariant is enforced**
330
+
331
+ - **Why:** A catalogued domain invariant is enforced, but `ark.config.json` does not name `coverage.coverageRoots` — the folders where the project says its test runner actually goes. Without that declaration, `INVARIANT_COVERAGE_OUTSIDE_ROOTS` cannot fire and coverage can certify a test no runner runs.
332
+ - **Fix:** Add `coverage.coverageRoots` in `ark.config.json` pointing at the folder the test runner uses, then re-run. `testGlobs` alone is not enough. Fail-closed until that path is present. Not freezable.
333
+
334
+ No enforced invariant, or roots already declared, stays silent. This is not a new config key. Promotion to enforced also refuses without roots.
335
+
336
+ <a id="INVARIANT_TESTS_PATH_MISSING"></a>
337
+
338
+ ### `INVARIANT_TESTS_PATH_MISSING`
339
+
340
+ **Domain-invariant tests path missing under adopted**
341
+
342
+ - **Why:** The project is adopted (required CI or explicit advisory) and has domain invariants that want test evidence, but `ark.config.json` does not name where those tests live. Green coverage without a real tests path is an empty checkbox.
343
+ - **Fix:** Add `coverage.testGlobs` or `coverage.coverageRoots` in `ark.config.json` pointing at a real tests folder, then re-run. Adopted mode fails closed until that path is present. Not freezable.
344
+
345
+ Not adopted, no catalogued invariants, or every invariant sets `coverage.test: false`, stays silent. This is not a new config key.
311
346
 
312
347
  ## ArkRun (opt-in extra)
313
348
 
@@ -589,8 +624,8 @@ Haken slaving: few slow keys (ξ) determine derived fast state. Field ingest nev
589
624
 
590
625
  **Lexical evidence incomplete**
591
626
 
592
- - **Why:** Single-file validation cannot prove project module resolution. The write hook is already the verdict.
593
- - **Fix:** Re-run `npx arkgate-check --root . --config ark.config.json`, or treat the hook deny as final. Do not call `ark_prepare_change` from a hook deny.
627
+ - **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.
628
+ - **Fix:** Run `npx arkgate-check --root . --config ark.config.json` to confirm. Do not call `ark_prepare_change` from a hook deny.
594
629
 
595
630
  <a id="ANALYSIS_COVERS_NO_FILES"></a>
596
631
 
@@ -598,7 +633,7 @@ Haken slaving: few slow keys (ξ) determine derived fast state. Field ingest nev
598
633
 
599
634
  **Analysis covered no files**
600
635
 
601
- - **Why:** No file matched the contract `include` and layer patterns under the analyzed root, so the run had nothing to check. Every rule is vacuously satisfied on an empty set: a green here would read exactly like a green over a governed tree while certifying nothing. Usual causes are a `--root` that is not the tree the contract describes (including a contract found outside the requested root, whose directory is then adopted as the project root), `include` / `exclude` patterns that match nothing, or layer patterns written for a different layout.
636
+ - **Why:** No file matched the contract `include` and layer patterns under the analyzed root, so the run had nothing to check. Every rule is vacuously satisfied on an empty set: a green here would read exactly like a green over a governed tree while certifying nothing. Usual causes are a `--root` that is not the tree the contract describes (including a contract found outside the requested root, whose directory is then adopted as the project root), `include` / `exclude` patterns that match nothing, layer patterns written for a different layout, or an `include` that matched files none of which belong to a layer.
602
637
  - **Fix:** Point `--root` at the tree the contract describes, or keep the contract inside that tree, or fix the `include` / `exclude` / layer patterns so they match real files — then re-run `npx arkgate-check --root . --config ark.config.json`. `--plan` and `--coverage` report the empty scope without refusing, and `--adopt-contract --write` proposes an `include` that matches the tree. This is a refusal about ArkGate's own inputs, not a finding about your code; no baseline or policy acknowledgement can suppress it, and `exclude` cannot silence it — the "is there source here" probe deliberately ignores the contract's own `exclude`, skips dot-directories, never follows a symlink, and skips `*.config.*` tooling files so a polyglot repo is not mistaken for a mismatch.
603
638
 
604
639
  <a id="ANALYSIS_HOST_UNAVAILABLE"></a>
@@ -850,6 +885,15 @@ never opting out of knowing.
850
885
  - **Why:** Included source files match no layer pattern; import rules will not enforce on them.
851
886
  - **Fix:** Extend layer patterns or narrow include so every governed file is classified.
852
887
 
888
+ <a id="CONFIG_LAYER_MISSING_OWNER"></a>
889
+
890
+ ### `CONFIG_LAYER_MISSING_OWNER`
891
+
892
+ **Layer missing owner**
893
+
894
+ - **Why:** `requireLayerOwners` is on and this layer has no owners. Writes to that house fail closed, like a folder with no name on the door.
895
+ - **Fix:** Add a GitHub handle or email to that layer’s owners in ark.config.json (`/ark-adopt`), then re-run. Reserved/allowEmpty houses may stay unnamed.
896
+
853
897
  ## Meta
854
898
 
855
899
  <a id="ARK_UNKNOWN"></a>
@@ -49,6 +49,11 @@ server with an explicit project root, compact Codex must contain valid project c
49
49
  SessionStart/PreToolUse Ark hooks, and CI must execute a fail-closed Ark command. Included but
50
50
  unclassified source files therefore remain red.
51
51
 
52
+ If gates are required and the tree has no short decision note yet (`docs/adr/` or
53
+ `docs/decisions/`), `--require-gates` and doctor point at that path. Soft hint —
54
+ not a fail, and silent when `--require-gates` is off. Not every change needs a
55
+ note; use one when you loosen a rule or add a real gate.
56
+
52
57
  Doctor JSON includes `writePath.mode` plus `enforcementLadder`: support, installation, observed
53
58
  evidence, covered operations, bypassability, and CI honesty. MCP registration stays advisory.
54
59
 
@@ -26,7 +26,7 @@ Run **`/ark-adopt`** on a greenfield or early-adoption repo (leftover `/ark-arch
26
26
  | `adoptInOrder.phase1` | Folders to create first |
27
27
  | `analogy` | Plain-language mental model |
28
28
  | `antiPatterns` | What Ark will block later |
29
- | `firstCommand` | Usually `ark init --archetype <id> --yes` |
29
+ | `firstCommand` | Usually `ark start --apply --archetype <id>` |
30
30
 
31
31
  Framework names appear only as secondary `toolHints` in JSON — never as the archetype label.
32
32
 
@@ -39,7 +39,7 @@ hardening guide remains repository-hosted rather than duplicated in the gate tar
39
39
 
40
40
  | Surface | How you use it | Stability notes |
41
41
  |---------|----------------|-----------------|
42
- | **CLI** | `arkgate` / `arkgate-check` (aliases `ark` / `ark-check`); optional ArkRun **`ark-dashboard`** / **`arkgate-dashboard`** | Flags and human text may improve; **JSON output shapes** for `--json` (check, doctor, plan, coverage, recommend, **status**, **agents-md**, **report**) are stable within a major. Additive fields OK; removals/renames are major. From 4.2, `--require-gates` implies strict config and verifies semantic Ark AGENTS, project-rooted MCP/compact Codex registration, and fail-closed CI rather than file presence alone. `ark status --json` is the unified status snapshot. `ark agents-md` is the version-matched agent projection (non-authoritative). **`arkgate report` / `ark report`** drafts an upstream GitHub issue for `pedroknigge/arkgate` (`package.json` `bugs.url`) — never the consumer repo. **Dashboard bins** poll an ArkRun inspector snapshot (ANSI + interval polling; `--url` / `--interval`); they are not a gate verdict. The main CLI also accepts `ark dashboard` / `arkgate dashboard` as a passthrough to those bins. |
42
+ | **CLI** | `arkgate` / `arkgate-check` (aliases `ark` / `ark-check`); optional ArkRun **`ark-dashboard`** / **`arkgate-dashboard`** | Flags and human text may improve; **JSON output shapes** for `--json` (check, doctor, plan, coverage, recommend, **status**, **agents-md**, **report**) are stable within a major. Additive fields OK; removals/renames are major. From 4.2, `--require-gates` implies strict config and verifies semantic Ark AGENTS, project-rooted MCP/compact Codex registration, and fail-closed CI rather than file presence alone. Soft ADR presence: when that demand (or doctor `required-merge`) is on and `docs/adr/` / `docs/decisions/` is missing, doctor JSON may add `adrPresence` and human copy points at a short decision note — never a fail, omitted when the demand is off. Soft states/transitions: when a conventional domain doc is already in play and the map is missing or heading-only, doctor JSON may add `statesTransitions` and human copy points at a short table (or one link) — never a fail, omitted when that doc is absent. Narrow status/transition catalog: when Domain-role code already names a closed status/state vocabulary and that map is still thin, doctor JSON may add `statusTransitionCatalog` with those names — never a fail, omitted when Domain has no such vocabulary, the domain doc is absent, or the map is already present. Soft no-Domain / UI-logic residual: when a Domain-role layer is declared but empty and presentation holds the tree (or `domain-logic-in-ui` is already present), doctor JSON may add `noDomainFrontend` and human copy points at one Domain file — never a fail, omitted when there is no frontend, Domain already has files, or the UI bag is too thin. Soft prototype-shortcut residual: when a Persistence-role layer is declared and SQLite or a JSON-file store lives outside it, or Domain / an auth tag is declared and admin / god-mode literals sit outside that house, doctor JSON may add `prototypeShortcuts` and human copy points at one Persistence adapter or Domain policy file — never a fail, omitted when those houses are absent, the shortcut is already in the right house, or there are no such markers. `ark status --json` is the unified status snapshot. `ark agents-md` is the version-matched agent projection (non-authoritative). **`arkgate report` / `ark report`** drafts an upstream GitHub issue for `pedroknigge/arkgate` (`package.json` `bugs.url`) — never the consumer repo. **Dashboard bins** poll an ArkRun inspector snapshot (ANSI + interval polling; `--url` / `--interval`); they are not a gate verdict. The main CLI also accepts `ark dashboard` / `arkgate dashboard` as a passthrough to those bins. |
43
43
  | **Upstream report CLI (4.8.10)** | `arkgate report` / `ark report` on the existing dual bins (no new bin, no new skill) | Default prints a draft for **upstream** `pedroknigge/arkgate` (`package.json` `bugs.url`) with the arkgate version and optional last-check snippet. Create only with `--submit` **and** `--i-confirm-submit` (after HITL) or TTY `Type submit to send`. `--yes` does not submit. Missing/unauthenticated `gh`: print the draft plus the exact `gh issue create --repo pedroknigge/arkgate` command, exit 2. Never files against the consumer repo. Not `ark-check --report` (HTML architecture report). |
44
44
  | **Host write boundaries** | Generated trusted PreToolUse/preToolUse hooks + `ark-mcp --hook`; inspect with doctor/status | Hard is always operation-scoped and runtime-evidenced. From 4.6.3, Codex CLI and local ChatGPT Desktop/App Server can hard-block a complete `apply_patch` sent as `tool_input.command`; `.codex/hooks.json` on disk remains unverified until a fresh covered invocation. Hosted tools, specialized hook opt-outs, shell/direct writes, incomplete reconstruction, and humans rely on required CI. Repair envelopes may emit, but Codex reinjection is not guaranteed. |
45
45
  | **Programmatic gate API** | `import { analyzeProject, loadContract, createAICodeGate, ... } from 'arkgate'` | The root export is the static gate/config/analysis contract listed below. It intentionally contains no runtime-kernel implementation. |
@@ -66,15 +66,17 @@ hardening guide remains repository-hosted rather than duplicated in the gate tar
66
66
  | **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`. |
67
67
  | **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. |
68
68
  | **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
- | **`ark.config.json`** | Layer globs, optional `layers[].description`, 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). |
69
+ | **`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). |
70
70
  | **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. |
71
+ | **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. |
72
+ | **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`. |
71
73
  | **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. |
72
74
  | **`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`. |
73
75
  | **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. |
74
76
  | **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`. |
75
77
  | **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. |
76
78
  | **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. |
77
- | **Team parliament (law vs feature)** | Optional `stewards` on `ark.config.json` (GitHub handle or email); CLI `--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. `stewards` and `layers[].description` are excluded from policy hash. Identity is handle or email, not git `user.name`. No org plane. |
79
+ | **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. |
78
80
  | **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. |
79
81
  | **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. |
80
82
  | **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. |
@@ -86,11 +88,11 @@ hardening guide remains repository-hosted rather than duplicated in the gate tar
86
88
  | **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. |
87
89
  | **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. |
88
90
  | **Agent contract projection** | CLI `ark agents-md [--write] [--check] [--stdout] [--json]`; install/upgrade AGENTS templates; root API `buildAgentProjectionBlock` / `mergeAgentProjectionDocument` | Schema `1.0` (projection markers). Version-stamped managed block (`arkgateVersion` + contract summary + diagnostic short list). **Non-authoritative** — not a gate input; enforcement is ark-check / hooks / CI. Content-identity merge preserves customized regions outside markers. Drift: `--check` vs package version. |
89
- | **Agent Skills packaging** | `templates/agent-skills/<name>/SKILL.md` (+ package README); root API `ARK_SKILL_NAMES` / `ARK_FIRST_CLASS_SKILL_NAMES` / `validateAgentSkillsPackage`; `npm run check:agent-skills` | Schema `1.0` (package contract). Closed catalog (`ARK_SKILL_NAMES`): first-class doors plus one-release stubs, 1:1 with flat `templates/skills/*.md`. First-class `/ark-order` (issue #216 / ADR 0036). Add a name only with a live ROADMAP item. |
91
+ | **Agent Skills packaging** | `templates/agent-skills/<name>/SKILL.md` (+ package README); root API `ARK_SKILL_NAMES` / `ARK_FIRST_CLASS_SKILL_NAMES` / `validateAgentSkillsPackage` / `validateSkillProductCapacity`; `npm run check:agent-skills` | Schema `1.0` (package contract). Closed catalog (`ARK_SKILL_NAMES`): first-class doors plus one-release stubs, 1:1 with flat `templates/skills/*.md`. First-class `/ark-order` (issue #216 / ADR 0036). `check:agent-skills` fails closed when a product plane or the north star drops out of skill bodies or living hubs. Add a name only with a live ROADMAP item. |
90
92
  | **`arkgate/schema/arkrules`** or **`arkgate/schema/ark.arkrules.schema.json`** | Per-layer structure sensors + invariant catalog (ADR 0012) | Schema `1.0`. Opt-in via root `arkRules` map (`ark.config` schema `1.1`). |
91
93
  | **`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. |
92
94
  | **Config JSON Schema** | `arkgate/schema` or `arkgate/schema/ark.config.schema.json` | Stable package resource subpaths for editor completion and contract tooling. |
93
- | **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`; drift `npm run check:agent-skills`. Skills never enforce. |
95
+ | **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. |
94
96
  | **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, and ArkOrder envelope (`ark/no-arkorder-kernel-in-domain`, `ark/no-arkorder-generic-update`) when `arkOrder` is on; loads consumer `ark.config.json`. Absence of an extra is silent. Missing-root / missing-plane and undeclared-* stay CLI/MCP. |
95
97
  | **GitHub Action** | `pedroknigge/arkgate` (see `action.yml`) | The `uses:` tag/SHA selects the checker source; `version` remains an optional exact npm compatibility override. |
96
98
  | **Package metadata** | `arkgate/package.json` | Stable resource subpath for tooling that needs the installed manifest. |
package/docs/use.md CHANGED
@@ -27,15 +27,22 @@ For **anyone** shipping TypeScript with an AI coding agent.
27
27
  npm install -D arkgate typescript
28
28
  npx arkgate start # preview what will change
29
29
  npx arkgate start --apply # install compact config + host router + CI; merge write-path gates into existing AGENTS.md / .mcp.json
30
- npx arkgate-check --doctor # status — one next step
31
- npx arkgate-check --doctor --all # full details
30
+ npx --package=arkgate arkgate-check --doctor # status — one next step
31
+ npx --package=arkgate arkgate-check --doctor --all # full details
32
32
  ```
33
33
 
34
+ `arkgate-check` is a command in the `arkgate` package, not its own npm package. After a local install, `npx arkgate-check --doctor` also works.
35
+
36
+ `start --apply` refuses when projected governed coverage is below 50% or
37
+ shape confidence is weak (below 0.6 with coverage under 80%). That lock is
38
+ deliberate. Lock the shape with `--archetype <id>`, `--preset <name>`, or
39
+ `--force`, or inspect ranked shapes with `npx arkgate-check --recommend`.
40
+
34
41
  Then keep working with your agent. Stuck? Run `--doctor` and do action **#1**. Compact first; `--all` for details.
35
42
 
36
43
  | Stuck on… | Do this |
37
44
  |-----------|---------|
38
- | Unsure | `npx arkgate-check --doctor` |
45
+ | Unsure | `npx --package=arkgate arkgate-check --doctor` |
39
46
  | Agent broke architecture | Fix the edge doctor names (or re-run check) |
40
47
  | Code is green but still a mess | Leftover design work — see below |
41
48
  | New ArkGate version | Follow doctor / upgrade guidance |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arkgate",
3
- "version": "4.8.14",
3
+ "version": "4.8.16",
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",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "https://unpkg.com/arkgate@2/schemas/ark.config.schema.json",
3
+ "$id": "https://unpkg.com/arkgate@4/schemas/ark.config.schema.json",
4
4
  "title": "ArkGate architecture contract",
5
5
  "description": "Versioned contract consumed identically by ArkGate CLI, MCP, and ESLint surfaces.",
6
6
  "type": "object",
@@ -16,7 +16,7 @@
16
16
  "$schema": {
17
17
  "type": "string",
18
18
  "minLength": 1,
19
- "default": "https://unpkg.com/arkgate@2/schemas/ark.config.schema.json",
19
+ "default": "https://unpkg.com/arkgate@4/schemas/ark.config.schema.json",
20
20
  "description": "Editor-facing URL or local path for this JSON Schema."
21
21
  },
22
22
  "schemaVersion": {
@@ -650,6 +650,9 @@
650
650
  },
651
651
  "uniqueItems": true,
652
652
  "default": []
653
+ },
654
+ "requireLayerOwners": {
655
+ "type": "boolean"
653
656
  }
654
657
  },
655
658
  "$defs": {
@@ -694,6 +697,24 @@
694
697
  "type": "string",
695
698
  "minLength": 1
696
699
  },
700
+ "trustBoundary": {
701
+ "type": "string",
702
+ "enum": [
703
+ "public",
704
+ "auth",
705
+ "admin",
706
+ "internal"
707
+ ]
708
+ },
709
+ "owners": {
710
+ "type": "array",
711
+ "items": {
712
+ "type": "string",
713
+ "minLength": 1
714
+ },
715
+ "uniqueItems": true,
716
+ "minItems": 1
717
+ },
697
718
  "forbiddenGlobals": {
698
719
  "type": "array",
699
720
  "items": {
@@ -837,7 +858,7 @@
837
858
  "coverage": {
838
859
  "type": "object",
839
860
  "additionalProperties": false,
840
- "description": "Invariant coverage scan controls. testGlobs replaces the built-in test-name heuristic; maxFiles raises or lowers the evidence file budget and also bounds structural-hint preload for orchestration-only, thin-adapter, and writes-via-aggregate (default 400; there is no arkrules.hintBudget); coverageRoots declares where the project runs its tests, so a covering test found outside them is reported instead of silently certifying an invariant.",
861
+ "description": "Invariant coverage scan controls. testGlobs replaces the built-in test-name heuristic; maxFiles raises or lowers the evidence file budget and also bounds structural-hint preload for orchestration-only, thin-adapter, and writes-via-aggregate (default 400; there is no arkrules.hintBudget); coverageRoots declares where the project runs its tests, so a covering test found outside them is reported instead of silently certifying an invariant. When any invariant is enforced, missing coverageRoots fails closed.",
841
862
  "properties": {
842
863
  "testGlobs": {
843
864
  "type": "array",
package/server.json CHANGED
@@ -6,12 +6,12 @@
6
6
  "url": "https://github.com/pedroknigge/arkgate",
7
7
  "source": "github"
8
8
  },
9
- "version": "4.8.14",
9
+ "version": "4.8.16",
10
10
  "packages": [
11
11
  {
12
12
  "registryType": "npm",
13
13
  "identifier": "arkgate",
14
- "version": "4.8.14",
14
+ "version": "4.8.16",
15
15
  "runtimeHint": "npx",
16
16
  "transport": {
17
17
  "type": "stdio"