arkgate 3.0.5 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/CHANGELOG.md +92 -1
  2. package/README.md +58 -21
  3. package/bin/ark-check.mjs +46 -4
  4. package/bin/ark-mcp.mjs +267 -26
  5. package/bin/ark.mjs +47 -0
  6. package/bin/lib/adapter-contract.mjs +27 -1
  7. package/bin/lib/analysis-engine.mjs +7 -1169
  8. package/bin/lib/ci-and-commands.mjs +4 -0
  9. package/bin/lib/contract-smells.mjs +514 -0
  10. package/bin/lib/doctor-plan.mjs +15 -4
  11. package/bin/lib/host-support-matrix.mjs +6 -2
  12. package/bin/lib/policy-delta-io.mjs +161 -0
  13. package/bin/lib/prepare-change.mjs +186 -0
  14. package/bin/lib/remediation.mjs +24 -0
  15. package/bin/lib/violations.mjs +2 -2
  16. package/bin/lib/write-path-capabilities.mjs +67 -1
  17. package/bin/lib/write-path-detect.mjs +4 -3
  18. package/dist/eslint/index.cjs +3 -977
  19. package/dist/eslint/index.js +3 -931
  20. package/dist/index.cjs +6 -1960
  21. package/dist/index.d.cts +152 -5
  22. package/dist/index.d.ts +152 -5
  23. package/dist/index.js +6 -1908
  24. package/docs/agent-guide.md +39 -5
  25. package/docs/ai-gates.md +17 -15
  26. package/docs/configuration.md +44 -0
  27. package/docs/demos/01-write-gate-self-correction.md +2 -2
  28. package/docs/enthusiast/README.md +5 -1
  29. package/docs/enthusiast/how-to-agent-gates.md +3 -5
  30. package/docs/enthusiast/how-to-policy-pack.md +4 -1
  31. package/docs/enthusiast/reference-archetypes.md +8 -1
  32. package/docs/enthusiast/reference-commands.md +8 -2
  33. package/docs/package-surface.md +12 -2
  34. package/docs/threat-model.md +10 -6
  35. package/package.json +7 -6
  36. package/schemas/ark.analysis-result.schema.json +5 -1
  37. package/schemas/ark.change-map.schema.json +77 -0
  38. package/server.json +3 -3
  39. package/docs/ark-check-example.json +0 -87
  40. package/docs/demos/03-copilot-autopilot.md +0 -93
  41. package/docs/migrate-from-ark-runtime-kernel.md +0 -174
  42. package/docs/production-hardening.md +0 -100
@@ -3,7 +3,9 @@
3
3
  **ArkGate** (`arkgate`) — architecture co-pilot for AI TypeScript. This guide describes how AI
4
4
  agents and codegen tools safely interact with write hooks, advisory MCP tools, CI, and `/ark-*`
5
5
  skills. Guarantees differ by host; start with the
6
- [canonical host support matrix](../README.md#host-enforcement-support).
6
+ [canonical host support matrix](../README.md#host-enforcement-support). The advisory-local /
7
+ hard-CI split is a deliberate trade-off, not a gap: local hooks and MCP coach at write time,
8
+ while a required merge status is the one boundary a repository can make every write path share.
7
9
 
8
10
  CLI names: prefer **`arkgate` / `arkgate-check` / `arkgate-mcp`**; aliases `ark` / `ark-check` /
9
11
  `ark-mcp` still work for one major. TypeScript **5.x / 6.x / 7.x** as the project compiler:
@@ -57,7 +59,8 @@ MCP `ark_recommend` and the `/ark-architect` skill.
57
59
  ### Terminal onboarding (Phase B)
58
60
 
59
61
  ```bash
60
- npx ark start --yes # preferred: shape → compact contract → active host → CI → plan
62
+ npx ark start --yes # preferred read-only preview: shape → contract → host → CI
63
+ npx ark start --yes --apply # apply exactly the previewed compact setup
61
64
  npx ark init --archetype crud-product --yes # non-interactive: shape → preset → origin → gates
62
65
  npx ark init # TTY wizard: pick application shape (1–8), not a framework
63
66
  npx ark-check --doctor # includes "New here?" when coverage is low or config is fresh
@@ -66,8 +69,8 @@ npx ark-check --watch # debounced re-check when govern
66
69
  ```
67
70
 
68
71
  **Day-zero origin (2.12+):** `ark init` freezes `.ark/reports/origin.*` before writing agent
69
- docs or CI templates. Compact `ark start` keeps first-run setup under five project files and
70
- 25 KB;
72
+ docs or CI templates. Compact `ark start` previews first and keeps the applied setup under five
73
+ project files and 25 KB;
71
74
  run `ark-check --report ark-report.html` explicitly when you want to establish an origin/evolution
72
75
  baseline. Do not `--reset-origin` unless the user explicitly wants a new baseline.
73
76
 
@@ -116,6 +119,23 @@ Smell **ids** (stable JSON) plus **outcome** lines (plain language, Q02) on each
116
119
  | `mixed-pattern-cluster` | Several layout styles — pick one golden pattern + pilot |
117
120
  | `soft-contract` | Layers without deny rules — add real walls, not soft green |
118
121
 
122
+ **Contract health (W01):** doctor JSON also carries `contractHealth` — a meta-lint of the
123
+ contract itself (never of the code): `contract-bidirectional-allow` (both directions explicitly
124
+ allowed between two layers), `contract-peripheral-depends-core` (audit/observability layer allowed
125
+ into orchestration/persistence), `contract-lateral-adapter-allow` (adapter layer allowed into a
126
+ sibling adapter layer), `contract-dead-rule` (rule references an empty or unknown layer, or is a
127
+ same-layer no-op; `optional: true` layers are exempt). Advisory only: it never changes the
128
+ verdict, `designFitness`, or `patternBets` — layer roles come from name heuristics, so treat a
129
+ miss as a warning to read, not a defect to silence. A deliberate edge is acknowledged in
130
+ `.ark/contract-smell-acks.json` (`{ acks: [{ id, edge, reason }] }`); `acknowledged` counts
131
+ applied acks only, and a malformed sidecar or edge string suppresses nothing.
132
+
133
+ **Governance weight (W02):** `contractHealth.governanceWeight` reports raw facts (layers, rules,
134
+ governed files, files/layer, rules/layer) plus a fixed band (`heavy` / `typical` / `light` /
135
+ `unknown`) with fixed wording. It is explicitly `notAScore` — never a gate input. Read `heavy` as
136
+ "justify the next layer/rule with demonstrated pressure", never as "delete layers"; read `light`
137
+ as "a boundary may be missing where violations concentrate".
138
+
119
139
  Each smell also has `evidence[]` paths and `message` (technical detail). Plan **B** bets include
120
140
  `pilot`, `successSignal`, `killSwitch`, and **`neverMechanicalSafe: true`** — loop/autoPatch must
121
141
  ignore them. For judgment I/O moves use **extraction cards**
@@ -281,14 +301,21 @@ Prefer preparing the write before the host commits it to disk:
281
301
  | Surface | Role |
282
302
  |---------|------|
283
303
  | MCP **`ark_prepare_write`** | Place + constrain + validate + optional `autoPatch` + `judgmentBrief` + contentHash + optional `goldenPattern` in one call |
304
+ | MCP **`ark_prepare_change`** | Validate one complete create/update/delete batch in memory; optional `changeMap` also returns structural convergence; never writes |
305
+ | CLI **`ark preflight --changes <file> --json`** | Same atomic verdict and map convergence for hosts/scripts that do not call MCP |
284
306
  | Write-gate **`autoPatch`** | Mechanical-safe **import type** rewrites only; post-patch revalidation green or discarded |
285
307
  | PreToolUse **`--hook-repair`** | On deny: `ARK_REPAIR_JSON` / `ARK_AUTOPATCH_JSON` on stderr (still exit 2 — never silent write) |
286
- | Doctor **`writePath`** | Reports `repair` \| `reject-only` \| `mcp-only` \| `none` for installed gates |
308
+ | Doctor **`writePath`** | Reports installed mode plus `enforcementLadder` (`supported` / `installed` / `active` / `bypassable`, evidence, operation coverage, required-status honesty) |
287
309
  | Doctor **`goldenPattern`** | Optional Q03 advisory summary (`present` / `invalid`); never clears design-weak |
288
310
 
289
311
  Port-proof inject binding is **judgment** for auto-apply (signature/arity change), not write-path autoPatch.
290
312
  Full reference: [ai-gates.md](ai-gates.md). Loop-cost harness: `npm run eval:loop-cost`.
291
313
 
314
+ Blocking diagnostics carry one deterministic `nextAction` in both human and JSON output. Complete
315
+ Codex `ApplyPatch` payloads use the same atomic batch engine as CLI/MCP before single-file safety
316
+ checks; this improves early feedback without upgrading Codex's bypassable hook to a universal hard
317
+ boundary. Removing `AGENTS.md`, skills, or session context never changes the contract verdict.
318
+
292
319
  Do not invent layers outside the 11-layer profile or named presets. Unrecognized
293
320
  directories (`utils/`, `lib/`) must be classified explicitly via `/ark-contract`.
294
321
 
@@ -672,6 +699,13 @@ The strongest place to constrain an AI agent is the moment it writes a file, not
672
699
  JS-API TypeScript — nested or project) so a host can gate
673
700
  the write path:
674
701
 
702
+ For a complete multi-file candidate, use `ark preflight --changes changes.json --json` or MCP
703
+ `ark_prepare_change`. Add `--change-map map.json` (or MCP `changeMap`) only for an explicit schema
704
+ `1.0` structural plan. Ark binds its normalized `changeMapHash` and compares the full candidate
705
+ against the current supplied base. `convergence.findings` separates satisfied, missing,
706
+ contradictory, and unplanned paths/edges; any structural mismatch rejects the batch. No map is
707
+ required, and `behavioralCompletion` remains `not-evaluated` even when structure converges.
708
+
675
709
  ```bash
676
710
  npx ark-mcp --root . --config ark.config.json [--manifest ark.manifest.json]
677
711
  ```
package/docs/ai-gates.md CHANGED
@@ -5,34 +5,29 @@ On Claude Code and Grok Build, an installed and trusted PreToolUse hook can bloc
5
5
  before they land on disk. Cursor and OpenAI Codex use advisory MCP validation at write time; CI is
6
6
  their hard repository check. Codex 0.123+ dispatches hooks for its native `apply_patch` handler,
7
7
  but Code Mode hosts can execute deferred nested writes without that project hook event. See the
8
- [canonical host support matrix](../README.md#host-enforcement-support) before installing.
8
+ [canonical host support matrix](../README.md#host-enforcement-support) before installing. The
9
+ advisory-local / hard-CI split is a deliberate trade-off: local surfaces optimize feedback speed,
10
+ while a required merge status is the one boundary a repository can make every write path share.
9
11
 
10
12
  Everything below uses the same `ark.config.json` as `arkgate-check` / `ark-check` (CI) — one
11
13
  contract shared by every surface. Generate it once:
12
14
 
13
15
  ```bash
14
16
  npx arkgate-check --init
15
- # aliases: ark-check, ark init, arkgate start
17
+ # aliases: ark-check --init, ark init
16
18
  ```
17
19
 
18
20
  For guided setup with prompts, use:
19
21
 
20
22
  ```bash
21
- npx arkgate start
23
+ npx arkgate start # read-only preview
24
+ npx arkgate start --apply # apply exactly the previewed setup
22
25
  # or: npx ark init
23
26
  ```
24
27
 
25
- `ark start` asks for the active agent on a TTY (or detects it otherwise) and applies a compact
26
- router setup: at most five project files and no `package.json` change unless you pass `--install`.
27
- Use `--tools <host>` to select the host explicitly. The broader command below remains the explicit
28
- way to install the full per-host `/ark-*` skill inventory.
29
-
30
- For non-interactive defaults, use:
31
-
32
- ```bash
33
- npx arkgate start --yes
34
- # or: npx ark init --yes
35
- ```
28
+ `ark start` detects one active host and previews a compact setup (≤5 files / 25 KB). Nothing is
29
+ written until `--apply`, which rejects stale inputs. Select a host with `--tools <host>`; use the
30
+ broader installer below only for the full `/ark-*` inventory.
36
31
 
37
32
  You can also generate only the starter gate files for common agent runtimes and CI:
38
33
 
@@ -48,7 +43,11 @@ you pass `--force`, so review and commit only the templates that match your proj
48
43
  **Doctor (W5):** `ark-check --doctor --json` includes `doctor.writePath`
49
44
  (`mode`: `repair` | `reject-only` | `mcp-only` | `none`, plus `prepareWrite` /
50
45
  `autoPatch` flags), the supported profile for the active host, and the evidence actually found.
51
- Supported capability and installed guarantee are deliberately separate.
46
+ `writePath.enforcementLadder` separates `supported`, `installed`, `active`, and `bypassable` for
47
+ local hooks, advisory MCP, and CI. Doctor leaves hook trust and required-status policy
48
+ `unverified`; an actual covered PreToolUse denial can report operation-scoped activity. Codex
49
+ `apply_patch` can expose a complete patch to the shared atomic preflight, but the host remains
50
+ bypassable/advisory because some Code Mode paths do not dispatch the project hook.
52
51
 
53
52
  **Design fitness (3.0.1+):** the same doctor JSON may include `doctor.designFitness` and
54
53
  `doctor.designSmells[]` (path evidence). Edge-clean `operatingMode: enforce` can still set
@@ -182,6 +181,9 @@ The MCP server exposes a resource and tools agents can use proactively (not an e
182
181
  - **`ark://manifest`** (resource) — the machine-readable architecture contract (layers + rules), so the agent can read the architecture before generating code.
183
182
  - **`validate_code`** (tool) — validates a snippet against the architecture on demand (the write-path gate). May return additive **`autoPatch`** (W1) for mechanical-safe import-type rewrites.
184
183
  - **`ark_prepare_write`** (tool) — **W2:** place + constrain + validate + optional autoPatch + judgmentBrief + contentHash in one call (composes `ark_place` + write gate).
184
+ - **`ark_prepare_change`** (tool) — **T02–T05:** read-only atomic create/update/delete preflight with cross-file edge/cycle findings and candidate fingerprints. Optional `changeMap` accepts strict schema `1.0` intent and returns its hash plus satisfied/missing/contradictory/unplanned structural convergence; behavioral completion is not evaluated. Omission is supported. MCP registration remains advisory unless the host makes invocation non-bypassable.
185
+ - Blocking CLI/MCP/hook diagnostics include the same deterministic `nextAction`. `AGENTS.md`, skill
186
+ catalogs, session prose, and live LLM calls are not inputs to the enforcement verdict.
185
187
  - **`ark_place`** (tool) — given a target file path, returns its layer, forbidden globals, and which layers it may / must not import. Call it *before* writing a new file so generated code lands in a governed location.
186
188
  - **`ark_check`** (tool) — runs the full architecture check and returns structured violations (applies the baseline automatically when one exists).
187
189
  - **`ark_coverage`** (tool) — per-layer file counts, the full unclassified-file list, and layers whose patterns match nothing.
@@ -95,3 +95,47 @@ Safety fields:
95
95
 
96
96
  The packaged JSON Schema is authoritative for types, constraints, defaults, and the unknown-key
97
97
  policy.
98
+
99
+ ## Contract transitions
100
+
101
+ `ark-check --strict-merge` protects the transition into a new contract, not only the resulting
102
+ file. In a Git checkout it compares the candidate `ark.config.json` with the merge base when that
103
+ base is available. CI can bind the comparison explicitly:
104
+
105
+ ```bash
106
+ ARK_POLICY_BASE_REF="$BASE_SHA" npx ark-check --strict-merge
107
+ ```
108
+
109
+ For local or non-Git automation, supply a committed config file or Git ref:
110
+
111
+ ```bash
112
+ npx ark-check --strict-config --policy-base ./before.ark.config.json --json
113
+ npx ark-check --strict-merge --policy-base-ref origin/main
114
+ ```
115
+
116
+ The additive JSON result includes `policyDelta`: both policy hashes, the overall classification,
117
+ stable findings, and `blockingFindingIds`. Supported comparisons cover governed include/exclude
118
+ roots, layer patterns/exclusions/forbidden globals, deny rules, same-layer peer isolation,
119
+ cycle policy, dynamic-import allowlists, and safety thresholds. Ambiguous ownership changes are
120
+ `judgment-required` rather than guessed.
121
+
122
+ Weakening and judgment-required transitions fail closed. An intentional exception is an explicit
123
+ JSON artifact passed with `--policy-ack`:
124
+
125
+ ```json
126
+ {
127
+ "schemaVersion": "1.0",
128
+ "basePolicyHash": "fnv1a-...",
129
+ "candidatePolicyHash": "fnv1a-...",
130
+ "findingIds": ["weakening:$.dynamicImportAllowlist:added"],
131
+ "reason": "Temporary loader while the static registry is migrated."
132
+ }
133
+ ```
134
+
135
+ The acknowledgement must list every blocking finding exactly. It is not a permanent allowlist:
136
+ changing either contract changes its hash and invalidates the acknowledgement.
137
+
138
+ MCP clients can call `ark_policy_delta` with the previous `baseConfig`, an optional candidate
139
+ contract (the current project contract is the default), and the same optional acknowledgement.
140
+ It invokes the public classifier directly, is read-only, and marks a blocking result as an MCP
141
+ error without maintaining separate adapter policy.
@@ -32,7 +32,7 @@ Add to the top of `src/domain/order.ts`:
32
32
  import { createInMemoryOrderRepository } from '../adapters/persistence/in-memory-order-repository.js';
33
33
  ```
34
34
 
35
- ### 3. Run the CI gate (same stimulus as the write-gate hook)
35
+ ### 3. Run the CI gate (same architecture contract as the write-gate hook)
36
36
 
37
37
  ```bash
38
38
  npm run check
@@ -71,4 +71,4 @@ Expected:
71
71
  - The fix is a file move or port inversion — not editing `ark.config.json`.
72
72
 
73
73
  See also: [Break it on purpose](../../examples/hexagonal-order-api/README.md#break-it-on-purpose)
74
- for two more exercises.
74
+ for two more exercises.
@@ -32,12 +32,14 @@ aliases `ark` / `ark-check` still work).
32
32
  | **Reference** | [Commands and artifacts](reference-commands.md) | `--recommend`, `--write-plan`, `ark-adoption-plan.json`, fix-class JSON |
33
33
  | **Explanation** | [Why application shape matters](explanation-application-shape.md) | Understand shapes vs frameworks and progressive phases |
34
34
 
35
- ## Public demos (Phase D)
35
+ ## Public demos
36
36
 
37
37
  Reproducible scripts — no video required:
38
38
 
39
39
  - [Write-gate self-correction](../demos/01-write-gate-self-correction.md)
40
40
  - [Brownfield baseline adoption](../demos/02-brownfield-baseline-adoption.md)
41
+ - [Co-pilot autopilot, end to end](../demos/03-copilot-autopilot.md)
42
+
41
43
  ## Gallery starters
42
44
 
43
45
  | Archetype | Directory |
@@ -46,6 +48,8 @@ Reproducible scripts — no video required:
46
48
  | `api-backend` | [examples/api-backend-starter](../../examples/api-backend-starter/) |
47
49
  | `worker-pipeline` | [examples/worker-pipeline-starter](../../examples/worker-pipeline-starter/) |
48
50
  | `multi-app-workspace` | [examples/multi-app-workspace-starter](../../examples/multi-app-workspace-starter/) |
51
+ | `vertical-slice-product` | [examples/vertical-slice-starter](../../examples/vertical-slice-starter/) |
52
+ | `ddd-bounded-contexts` | [examples/ddd-context-starter](../../examples/ddd-context-starter/) |
49
53
 
50
54
  Deep teaching example (runnable API + break exercises): [hexagonal-order-api](../../examples/hexagonal-order-api/).
51
55
 
@@ -21,7 +21,7 @@ Installs:
21
21
  |------|-------------|
22
22
  | Claude Code | `.claude/settings.json`, `.claude/skills/` |
23
23
  | Cursor | `.cursor/mcp.json`, `.cursor/rules/ark.mdc`, `.cursor/commands/` |
24
- | Codex | `docs/ark-codex-config.toml` + home MCP/prompts |
24
+ | Codex | `.codex/hooks.json`, `.agents/skills/`; MCP in `$CODEX_HOME/config.toml` |
25
25
  | **Grok Build** | `.grok/config.toml`, `.grok/hooks/`, `.grok/skills/` |
26
26
 
27
27
  See the [canonical host support matrix](../../README.md#host-enforcement-support) for the exact
@@ -42,10 +42,8 @@ npx arkgate-check --doctor
42
42
  npx arkgate-check --require-gates
43
43
  ```
44
44
 
45
- Doctor JSON (`--doctor --json`) includes **`writePath`**: the active host's supported profile,
46
- installed evidence, and whether PreToolUse is
47
- `repair` (machine-readable autoPatch on deny), `reject-only`, `mcp-only`, or
48
- `none` — plus `prepareWrite` / `autoPatch` booleans for leads.
45
+ Doctor JSON includes `writePath.mode` plus `enforcementLadder`: support, installation, observed
46
+ evidence, covered operations, bypassability, and CI honesty. MCP registration stays advisory.
49
47
 
50
48
  After upgrading the package, refresh skills so agents see the latest plan kinds:
51
49
 
@@ -15,6 +15,9 @@ Available packs:
15
15
  - `enthusiast-layered`
16
16
  - `enthusiast-feature-sliced`
17
17
  - `enthusiast-monorepo`
18
+ - `enthusiast-ui-surface`
19
+ - `enthusiast-vertical-slice`
20
+ - `enthusiast-ddd-bounded-contexts`
18
21
 
19
22
  ## Apply
20
23
 
@@ -34,4 +37,4 @@ Monorepo packs detect workspace roots from `package.json` / `pnpm-workspace.yaml
34
37
  | Application shape (todo app, API, …) | `ark-check --recommend` → `ark init --archetype` |
35
38
  | Preset name only | `--apply-policy-pack enthusiast-<preset>` |
36
39
 
37
- `ark-adoption-plan.json` from `--write-plan` includes a suggested `policyPack` id matching the recommended preset.
40
+ `ark-adoption-plan.json` from `--write-plan` includes a suggested `policyPack` id matching the recommended preset.
@@ -16,6 +16,8 @@ Authoritative source: `templates/architecture-playbook.json` (shipped in the npm
16
16
  | `integration-bridge` | System glue | `hexagonal` |
17
17
  | `multi-app-workspace` | Monorepo | `monorepo` |
18
18
  | `prototype-spike` | Quick experiment | `layered` |
19
+ | `vertical-slice-product` | Feature-first product | `vertical-slice` |
20
+ | `ddd-bounded-contexts` | Multiple business domains | `ddd-bounded-contexts` |
19
21
 
20
22
  ## Named presets
21
23
 
@@ -25,6 +27,9 @@ Authoritative source: `templates/architecture-playbook.json` (shipped in the npm
25
27
  | `layered` | `enthusiast-layered` |
26
28
  | `feature-sliced` | `enthusiast-feature-sliced` |
27
29
  | `monorepo` | `enthusiast-monorepo` |
30
+ | `ui-surface` | `enthusiast-ui-surface` |
31
+ | `vertical-slice` | `enthusiast-vertical-slice` |
32
+ | `ddd-bounded-contexts` | `enthusiast-ddd-bounded-contexts` |
28
33
 
29
34
  ## Gallery mapping
30
35
 
@@ -33,4 +38,6 @@ Authoritative source: `templates/architecture-playbook.json` (shipped in the npm
33
38
  | `crud-product` | `examples/crud-product-starter/` |
34
39
  | `api-backend` | `examples/api-backend-starter/` |
35
40
  | `worker-pipeline` | `examples/worker-pipeline-starter/` |
36
- | `multi-app-workspace` | `examples/multi-app-workspace-starter/` |
41
+ | `multi-app-workspace` | `examples/multi-app-workspace-starter/` |
42
+ | `vertical-slice-product` | `examples/vertical-slice-starter/` |
43
+ | `ddd-bounded-contexts` | `examples/ddd-context-starter/` |
@@ -37,16 +37,22 @@ Pack metadata: `templates/policy-packs/enthusiast-*.json`.
37
37
  ## Init and verify
38
38
 
39
39
  ```bash
40
- arkgate start --yes # guided setup + plan
40
+ arkgate start --yes # read-only setup preview with non-interactive defaults
41
+ arkgate start --yes --apply # apply exactly that preview
41
42
  ark init --archetype <id> --yes # alias path
42
43
  arkgate-check --doctor [--json]
43
44
  arkgate-check --coverage [--json]
44
45
  arkgate-check --plan [--json] # mechanical-safe vs judgment vs deferred
45
46
  arkgate-check --strict-config
47
+ arkgate-check --strict-merge
48
+ arkgate preflight --changes changes.json [--change-map map.json] --json
46
49
  arkgate-check --report out.html --beginner
47
50
  arkgate-check --watch
48
51
  ```
49
52
 
53
+ In 3.1+, strict merge protects policy changes; preflight checks one complete batch without writing
54
+ (`--change-map` adds structural convergence). MCP: `ark_policy_delta`, `ark_prepare_change`.
55
+
50
56
  ## Plan classes (`--plan --json`)
51
57
 
52
58
  | `class` | Agent may auto-apply? | Examples (`remediationKind`) |
@@ -62,4 +68,4 @@ When present on violations:
62
68
  - `fixClass` — e.g. `port-inversion`, `file-move`
63
69
  - `effort` — `small` | `medium`
64
70
  - `enthusiastHint` — plain English fix guidance
65
- - plan enrichment: `class`, `remediationKind`, `typeOnly`, `sourcePureTypeModule`, `targetTypeOnlyExports`, `namedBindingsTypeOnly`
71
+ - plan enrichment: `class`, `remediationKind`, `typeOnly`, `sourcePureTypeModule`, `targetTypeOnlyExports`, `namedBindingsTypeOnly`
@@ -7,6 +7,8 @@
7
7
  In-repo `docs/` remains the package/agent reference. Source: GitHub; distribution: npm.
8
8
 
9
9
  This document is the consumer contract for **what is stable** vs **what is experimental**.
10
+ It ships as the consumer contract linked from the npm README. The separate experimental-runtime
11
+ hardening guide remains repository-hosted rather than duplicated in the gate tarball.
10
12
 
11
13
  ---
12
14
 
@@ -21,9 +23,16 @@ This document is the consumer contract for **what is stable** vs **what is exper
21
23
  | **Plan pattern B (P03+)** | `ark-check --plan --json` → `plan.patternBets[]`, `plan.goal.designWeak` | Additive. Each bet: `id`, `smellId`, `pilot`, `evidence`, `successSignal`, `killSwitch`, **`neverMechanicalSafe: true`**, `class: "judgment"`. **Never** auto-applied by loop/autoPatch; not a `remediationKind` mechanical-safe. `goal.met` remains edge honesty only. |
22
24
  | **Pilot loop (Q04)** | `plan.pilotLoop` / `doctor.pilotLoop` | Additive. When design-weak: `active`, `oneAtATime`, `neverMechanicalSafe`, **`nextPilot`** extraction-card fields (`pilotTarget`, `smellId`, `move`, `successSignal`, `killSwitch`, `doNot[]`). **One pilot → re-doctor**; never multi-pilot batch; never mechanical-safe. |
23
25
  | **AI-velocity eval (Q05)** | `npm run eval:ai-velocity` → `eval/ai-velocity-report.json` | Fixture-measured (no live LLM). Same feature scenario on design-weak vs golden-path arms; metric **`placementTurns`** (agent-equivalent). Golden must be strictly better. Method string lives next to the number. Does not weaken the gate. |
26
+ | **Contract health (W01)** | `ark-check --doctor --json` → `doctor.contractHealth`; optional `.ark/contract-smell-acks.json` | Additive, **advisory only** — meta-lint of the contract itself (layer-name heuristics; imprecision costs a warning line, never a verdict); never changes the verdict, `designFitness`, or `patternBets`. Stable smell ids: `contract-bidirectional-allow`, `contract-peripheral-depends-core`, `contract-lateral-adapter-allow`, `contract-dead-rule`; each smell has `severity`, `evidence[]` (sorted, honest `…(+N more)` truncation), `fix`, `message`, plain-language `outcome`, and `acknowledgedEdges` (acks applied to that id). Acknowledgments live in the bounded sidecar (`{ acks: [{ id, edge, reason }] }`, ≤64 KB / ≤200 entries; bidirectional edges order-insensitive, exact two segments); `contractHealth.acknowledged` counts **applied** acks only (stale acks count 0). **Absent is normal**; malformed file or edge grammar → ignored + `ackFile.invalid` where applicable, never silent suppression. |
27
+ | **Governance weight (W02)** | `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`. |
24
28
  | **MCP tools** | `arkgate-mcp` / `ark://…` resources | Tool names and primary argument shapes are stable within a major. |
25
29
  | **`ark.config.json`** | Layer globs, rules, include/exclude, forbiddenGlobals, intent prefixes, `peerIsolation`, `dynamicImportAllowlist`, `safety` thresholds | Versioned by `schemaVersion`; unknown fields fail closed and migrations preserve the previous supported major. |
26
- | **`arkgate/schema/analysis-result`** | Public CLI/MCP/hook diagnostic envelope (`schemaVersion`, `valid`, `diagnostics`) | Versioned JSON Schema; committed v1 compatibility fixture protects rule, severity, location, and evidence fields. |
30
+ | **Policy transition analysis (T01, 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. |
31
+ | **Atomic change preflight (T02, 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. |
32
+ | **Architecture change map (T03, 3.1.0)** | `arkgate/schema/change-map`; 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. |
33
+ | **Structural convergence (T04, 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. |
34
+ | **Enforcement ladder + fixed journey (T05, 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. |
35
+ | **`arkgate/schema/analysis-result`** | Public CLI/MCP/hook diagnostic envelope (`schemaVersion`, `valid`, `diagnostics`) | Schema `1.1` adds optional `nextAction`; the `1.0` fixture and consumer-owned TypeScript diagnostics remain valid. |
27
36
  | **Config JSON Schema** | `arkgate/schema` or `arkgate/schema/ark.config.schema.json` | Stable package resource subpaths for editor completion and contract tooling. |
28
37
  | **Agent skills** | `/ark-*` templates installed by `--install-agent-gates` | Skill *names* and “default flow” are stable; internal skill prose may evolve (e.g. When/not when, explore Shape dual-plan seed, extraction cards, day-zero origin order). |
29
38
  | **ESLint subpath** | `arkgate/eslint` | Config-driven layer/import rules; loads consumer `ark.config.json`. |
@@ -84,5 +93,6 @@ production deployment would need to satisfy; it is not a readiness certification
84
93
 
85
94
  ## Release notes (maintainers)
86
95
 
87
- Ship notes for a version live under [releases/](./releases/) (e.g. [2.12.0.md](./releases/2.12.0.md)).
96
+ Ship notes for a version live under [releases/](./releases/) (latest:
97
+ [3.2.0.md](./releases/3.2.0.md)).
88
98
  Publish path: signed annotated tag → GitHub Release → `publish-npm.yml` (see [CONTRIBUTING.md](../CONTRIBUTING.md)).
@@ -1,4 +1,4 @@
1
- # Threat model — ArkGate (Q9)
1
+ # Threat model — ArkGate
2
2
 
3
3
  **Scope:** architecture write/CI gates, agent hooks/MCP, and the experimental optional runtime.
4
4
  **Not in scope:** full org identity platforms, browser XSS in consumer apps, or npm registry
@@ -27,21 +27,24 @@ infrastructure beyond how this package is published.
27
27
 
28
28
  | ID | Threat | Impact | Mitigations (shipped) |
29
29
  |----|--------|--------|------------------------|
30
- | T1 | Agent bypasses hook (direct `fs` / alternate tool) | Ungoverned code lands | CI gate; optional pre-commit (Q3); doctor writePath honesty |
30
+ | T1 | Agent bypasses hook (direct `fs` / alternate tool) | Ungoverned code lands | CI gate; optional pre-commit (Q3); doctor ladder never upgrades installed files to active/hard proof |
31
31
  | T2 | Human commits without agent path | Same as T1 | `templates/hooks/pre-commit-ark`; branch protection + required check (Q3 external) |
32
- | T3 | CI job missing / not required | Merge green without architecture | doctor `enforcement-ci-*` gaps; `--strict-merge` profile |
33
- | T4 | Config weakened (`peerIsolation: false`, empty rules) | False green | safety diagnostics; false-green adoption detector |
32
+ | T3 | CI job missing / not required | Merge green without architecture | doctor `enforcement-ci-*` gaps; `--strict-merge`; required-status remains locally `unverified` |
33
+ | T4 | Config weakened (`peerIsolation: false`, empty rules) | False green | semantic policy-delta guard in strict merge; hash-bound explicit acknowledgement; present-state safety diagnostics |
34
34
  | T5 | Baseline ratcheted open | Debt reintroduced | baseline unused/stale signals; occurrence keys |
35
35
  | T6 | Dual MCP bin / wrong root | Gate points at wrong tree | migrate-commands; Codex fail-closed temp roots |
36
36
  | T7 | Malicious dependency in publish | Compromised gate | signed tags, npm provenance, dependency-review, CodeQL, Semgrep, `verify-package-files` |
37
37
  | T8 | Path traversal in hooks/check | Read/write outside project | root resolution + under-root import resolve |
38
38
  | T9 | Runtime InMemory mistaken for durable | Data loss | durability stance docs + safety InMemory production detector |
39
39
  | T10 | Repair payload silently applied | Unexpected rewrites | repair never writes; host must re-inject; exit 2 on deny |
40
+ | T11 | Prompt context is mistaken for enforcement | Verdict changes after compaction or missing skills | contract/tree inputs only; no-context eval compares hashes and adapter evidence |
41
+ | T12 | Partial multi-file hook validation misses a cross-file edge | Invalid batch reaches disk | complete `apply_patch` events use atomic preflight; incomplete/bypassable paths rely on CI |
40
42
 
41
43
  ## Trust boundaries
42
44
 
43
45
  ```
44
- Claude/Grok host --PreToolUse--> arkgate-mcp (hard matched-write boundary)
46
+ Claude/Grok host --PreToolUse--> arkgate-mcp (hard only for observed covered operation)
47
+ Codex ApplyPatch --PreToolUse--> arkgate-mcp (atomic feedback; bypassable/non-hard host profile)
45
48
  Any MCP host --tool call----> arkgate-mcp (advisory validation)
46
49
  Human IDE --disk/git-----> working tree
47
50
  working tree --PR-----------> CI ark-check --strict-merge
@@ -51,7 +54,8 @@ npm publish <-- signed tag --- GitHub Release + provenance
51
54
  ## Residual risk (accepted)
52
55
 
53
56
  - Branch protection is **external GitHub state** — doctor reports honestly when unavailable.
54
- - Full external adoption matrix (Q4) and independent ≥95 audit (Q10) are separate exit gates.
57
+ - External adoption and independent-audit evidence are release snapshots bound to pinned commits;
58
+ they do not prove every repository layout or future host version.
55
59
  - Live multi-agent loop-cost remains optional (`ARK_EVAL_LOOP_LIVE`).
56
60
 
57
61
  ## Verification hooks
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arkgate",
3
- "version": "3.0.5",
3
+ "version": "3.2.0",
4
4
  "description": "ArkGate — architecture co-pilot for AI TypeScript (write gate, CI gate, plan/loop)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -26,6 +26,8 @@
26
26
  "./schema/ark.config.schema.json": "./schemas/ark.config.schema.json",
27
27
  "./schema/analysis-result": "./schemas/ark.analysis-result.schema.json",
28
28
  "./schema/ark.analysis-result.schema.json": "./schemas/ark.analysis-result.schema.json",
29
+ "./schema/change-map": "./schemas/ark.change-map.schema.json",
30
+ "./schema/ark.change-map.schema.json": "./schemas/ark.change-map.schema.json",
29
31
  "./nestjs": {
30
32
  "types": "./compat/nestjs.d.ts",
31
33
  "import": "./compat/nestjs.js",
@@ -50,16 +52,14 @@
50
52
  "schemas",
51
53
  "docs/agent-guide.md",
52
54
  "docs/enthusiast",
53
- "docs/demos",
55
+ "docs/demos/01-write-gate-self-correction.md",
56
+ "docs/demos/02-brownfield-baseline-adoption.md",
54
57
  "docs/ai-gates.md",
55
- "docs/migrate-from-ark-runtime-kernel.md",
56
58
  "docs/typescript-support.md",
57
- "docs/ark-check-example.json",
58
59
  "docs/assets",
59
60
  "docs/brownfield-adoption.md",
60
61
  "docs/configuration.md",
61
62
  "docs/package-surface.md",
62
- "docs/production-hardening.md",
63
63
  "docs/threat-model.md",
64
64
  "tests/fixtures/ts-consumer",
65
65
  "templates",
@@ -105,6 +105,7 @@
105
105
  "eval:comparative": "node eval/comparative-run.mjs",
106
106
  "eval:loop-cost": "node eval/loop-cost-run.mjs",
107
107
  "eval:ai-velocity": "node eval/ai-velocity-run.mjs",
108
+ "eval:change-integrity": "node eval/change-integrity-run.mjs",
108
109
  "eval:adoption": "node eval/adoption-run.mjs",
109
110
  "test:adoption-harness": "vitest run tests/unit/eval/adoptionHarness.test.ts",
110
111
  "bench:scale": "node scripts/ark-scale-bench.mjs",
@@ -119,7 +120,7 @@
119
120
  "prepack": "npm run build"
120
121
  },
121
122
  "dependencies": {
122
- "typescript": "^5.9.3"
123
+ "typescript": ">=5.0.0 <8"
123
124
  },
124
125
  "peerDependencies": {
125
126
  "@arkgate/runtime": ">=0.1.0-experimental.0 <1",
@@ -11,7 +11,7 @@
11
11
  ],
12
12
  "properties": {
13
13
  "schemaVersion": {
14
- "const": "1.0"
14
+ "const": "1.1"
15
15
  },
16
16
  "valid": {
17
17
  "type": "boolean"
@@ -83,6 +83,10 @@
83
83
  "type": "boolean"
84
84
  }
85
85
  }
86
+ },
87
+ "nextAction": {
88
+ "type": "string",
89
+ "minLength": 1
86
90
  }
87
91
  }
88
92
  }
@@ -0,0 +1,77 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://unpkg.com/arkgate@3/schemas/ark.change-map.schema.json",
4
+ "title": "ArkGate architecture change map",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": [
8
+ "$schema",
9
+ "schemaVersion",
10
+ "files"
11
+ ],
12
+ "properties": {
13
+ "$schema": {
14
+ "type": "string",
15
+ "minLength": 1,
16
+ "default": "https://unpkg.com/arkgate@3/schemas/ark.change-map.schema.json"
17
+ },
18
+ "schemaVersion": {
19
+ "type": "string",
20
+ "const": "1.0",
21
+ "default": "1.0"
22
+ },
23
+ "files": {
24
+ "type": "array",
25
+ "minItems": 1,
26
+ "items": {
27
+ "type": "object",
28
+ "additionalProperties": false,
29
+ "required": [
30
+ "path",
31
+ "operation",
32
+ "layer"
33
+ ],
34
+ "properties": {
35
+ "path": {
36
+ "type": "string",
37
+ "minLength": 1
38
+ },
39
+ "operation": {
40
+ "type": "string",
41
+ "enum": [
42
+ "create",
43
+ "update",
44
+ "delete"
45
+ ]
46
+ },
47
+ "layer": {
48
+ "type": "string",
49
+ "minLength": 1
50
+ }
51
+ }
52
+ }
53
+ },
54
+ "dependencies": {
55
+ "type": "array",
56
+ "default": [],
57
+ "items": {
58
+ "type": "object",
59
+ "additionalProperties": false,
60
+ "required": [
61
+ "from",
62
+ "to"
63
+ ],
64
+ "properties": {
65
+ "from": {
66
+ "type": "string",
67
+ "minLength": 1
68
+ },
69
+ "to": {
70
+ "type": "string",
71
+ "minLength": 1
72
+ }
73
+ }
74
+ }
75
+ }
76
+ }
77
+ }
package/server.json CHANGED
@@ -1,17 +1,17 @@
1
1
  {
2
2
  "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
3
3
  "name": "io.github.pedroknigge/arkgate",
4
- "description": "ArkGate architecture co-pilot for AI TypeScript (write gate, CI, plan/loop)",
4
+ "description": "ArkGate \u2014 architecture co-pilot for AI TypeScript (write gate, CI, plan/loop)",
5
5
  "repository": {
6
6
  "url": "https://github.com/pedroknigge/arkgate",
7
7
  "source": "github"
8
8
  },
9
- "version": "3.0.5",
9
+ "version": "3.2.0",
10
10
  "packages": [
11
11
  {
12
12
  "registryType": "npm",
13
13
  "identifier": "arkgate",
14
- "version": "3.0.5",
14
+ "version": "3.2.0",
15
15
  "runtimeHint": "npx",
16
16
  "transport": {
17
17
  "type": "stdio"