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.
- package/CHANGELOG.md +92 -1
- package/README.md +58 -21
- package/bin/ark-check.mjs +46 -4
- package/bin/ark-mcp.mjs +267 -26
- package/bin/ark.mjs +47 -0
- package/bin/lib/adapter-contract.mjs +27 -1
- package/bin/lib/analysis-engine.mjs +7 -1169
- package/bin/lib/ci-and-commands.mjs +4 -0
- package/bin/lib/contract-smells.mjs +514 -0
- package/bin/lib/doctor-plan.mjs +15 -4
- package/bin/lib/host-support-matrix.mjs +6 -2
- package/bin/lib/policy-delta-io.mjs +161 -0
- package/bin/lib/prepare-change.mjs +186 -0
- package/bin/lib/remediation.mjs +24 -0
- package/bin/lib/violations.mjs +2 -2
- package/bin/lib/write-path-capabilities.mjs +67 -1
- package/bin/lib/write-path-detect.mjs +4 -3
- package/dist/eslint/index.cjs +3 -977
- package/dist/eslint/index.js +3 -931
- package/dist/index.cjs +6 -1960
- package/dist/index.d.cts +152 -5
- package/dist/index.d.ts +152 -5
- package/dist/index.js +6 -1908
- package/docs/agent-guide.md +39 -5
- package/docs/ai-gates.md +17 -15
- package/docs/configuration.md +44 -0
- package/docs/demos/01-write-gate-self-correction.md +2 -2
- package/docs/enthusiast/README.md +5 -1
- package/docs/enthusiast/how-to-agent-gates.md +3 -5
- package/docs/enthusiast/how-to-policy-pack.md +4 -1
- package/docs/enthusiast/reference-archetypes.md +8 -1
- package/docs/enthusiast/reference-commands.md +8 -2
- package/docs/package-surface.md +12 -2
- package/docs/threat-model.md +10 -6
- package/package.json +7 -6
- package/schemas/ark.analysis-result.schema.json +5 -1
- package/schemas/ark.change-map.schema.json +77 -0
- package/server.json +3 -3
- package/docs/ark-check-example.json +0 -87
- package/docs/demos/03-copilot-autopilot.md +0 -93
- package/docs/migrate-from-ark-runtime-kernel.md +0 -174
- package/docs/production-hardening.md +0 -100
package/CHANGELOG.md
CHANGED
|
@@ -4,7 +4,98 @@ All notable changes to ArkGate (`arkgate`; formerly `ark-runtime-kernel`) are do
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## 3.2.0 — 2026-07-15
|
|
8
|
+
|
|
9
|
+
Contract health (Phase W): ArkGate now also meta-lints the contract itself and describes its
|
|
10
|
+
governance weight, and the docs name the enforcement-boundary trade-off explicitly. Everything in
|
|
11
|
+
this release is **advisory only** — no verdict, `designFitness`, `patternBets`, or gate result
|
|
12
|
+
changes. **No breaking** CLI or `ark.config.json` changes. **No gate weaken.**
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- **W01 contract smells:** `ark-check --doctor --json` gains `doctor.contractHealth` with four
|
|
17
|
+
stable, deterministic smell ids that lint the contract rather than the code:
|
|
18
|
+
`contract-bidirectional-allow` (both directions explicitly allowed between two layers),
|
|
19
|
+
`contract-peripheral-depends-core` (audit/observability layer allowed into
|
|
20
|
+
orchestration/persistence), `contract-lateral-adapter-allow` (adapter layer allowed into a
|
|
21
|
+
sibling adapter layer), and `contract-dead-rule` (rule referencing an unknown or empty layer, or
|
|
22
|
+
a same-layer no-op; `optional: true` layers are exempt). Each smell carries `severity`,
|
|
23
|
+
sorted `evidence[]` with honest `…(+N more)` truncation, technical `message`, plain-language
|
|
24
|
+
`outcome`, and `fix`. Human doctor prints a "Contract health (advisory)" section.
|
|
25
|
+
- **Acknowledgment sidecar:** deliberate edges are recorded in an optional
|
|
26
|
+
`.ark/contract-smell-acks.json` (`{ acks: [{ id, edge, reason }] }`; bidirectional edges
|
|
27
|
+
order-insensitive) — the versioned `ark.config.json` schema is untouched. The file is bounded
|
|
28
|
+
(≤64 KB, ≤200 entries); a malformed file or edge grammar is reported via `ackFile.invalid` and
|
|
29
|
+
never suppresses a smell. `contractHealth.acknowledged` counts applied acks only.
|
|
30
|
+
- **W02 governance weight:** `doctor.contractHealth.governanceWeight` reports raw facts
|
|
31
|
+
(declared/populated layers, governed files, rules, denied/allowed edges, files-per-layer,
|
|
32
|
+
rules-per-layer) plus a fixed comparative band — `heavy` (fewer than 25 governed files per layer
|
|
33
|
+
AND 6+ layers or 4+ rules per layer), `light` (≤2 layers over 150+ governed files), `typical`,
|
|
34
|
+
or `unknown` — with fixed wording and an explicit `notAScore: true`. Banding uses raw ratios;
|
|
35
|
+
reported ratios are rounded for display. The heavy note asks to justify NEW layers with
|
|
36
|
+
demonstrated pressure and never suggests deleting working ones.
|
|
37
|
+
- **W03 enforcement-boundary positioning:** README explains why the hard guarantee lives at the
|
|
38
|
+
required merge status ("deliberate trade-off, not a gap"; the contract doubles as a pressure
|
|
39
|
+
sensor), and `docs/ai-gates.md` / `docs/agent-guide.md` carry the same framing next to the
|
|
40
|
+
canonical host support matrix. A docs regression pins the wording without strengthening any
|
|
41
|
+
guarantee claim.
|
|
42
|
+
|
|
43
|
+
### Fixed
|
|
44
|
+
|
|
45
|
+
- Contract meta-lint reads the rules actually in force (manifest-aware), not only `config.rules`.
|
|
46
|
+
- Hostile ack-file inputs (FIFO/symlink targets, oversized files, sloppy edge strings) can no
|
|
47
|
+
longer hang `--doctor`, exhaust memory, or silently suppress findings; null rule entries and
|
|
48
|
+
malformed coverage rows no longer throw.
|
|
49
|
+
- Governance-weight banding is size-relative in both clauses: a large tree with a proportionate
|
|
50
|
+
dense rule matrix never reads `heavy`, and NaN/negative counts read `unknown`.
|
|
51
|
+
|
|
52
|
+
## 3.1.0 — 2026-07-15
|
|
53
|
+
|
|
54
|
+
Deterministic change integrity. **No breaking** CLI or `ark.config.json` changes. **No gate
|
|
55
|
+
weaken.**
|
|
56
|
+
|
|
57
|
+
### Added
|
|
58
|
+
|
|
59
|
+
- **T01 policy-transition guard:** the public analysis API and generated CLI engine classify
|
|
60
|
+
`ark.config.json` changes as `strengthening`, `neutral`, `judgment-required`, or `weakening`.
|
|
61
|
+
`--strict-merge` compares the Git merge-base contract when available; explicit
|
|
62
|
+
`--policy-base` / `--policy-base-ref` inputs are also supported.
|
|
63
|
+
- **Hash-bound acknowledgement:** weakening and judgment-required findings fail until
|
|
64
|
+
`--policy-ack` supplies the exact base/candidate policy hashes, complete finding-id set, and a
|
|
65
|
+
non-empty reason. Any later contract edit invalidates the acknowledgement.
|
|
66
|
+
- **CI base provenance:** generated workflows fetch full history and the composite Action passes
|
|
67
|
+
the PR/push base SHA through `ARK_POLICY_BASE_REF`.
|
|
68
|
+
- **MCP parity:** `ark_policy_delta` exposes the same read-only classifier for explicit base and
|
|
69
|
+
candidate contracts and returns blocking transitions as tool errors.
|
|
70
|
+
- **T02 atomic change preflight:** public `preflightChange(...)`, CLI
|
|
71
|
+
`ark preflight --changes <change-set.json>`, and MCP `ark_prepare_change` evaluate one complete
|
|
72
|
+
create/update/delete candidate without writing. Schema `1.0` includes per-file content
|
|
73
|
+
fingerprints plus policy, compiler, base-tree, and candidate-tree fingerprints.
|
|
74
|
+
- **Batch safety:** duplicate normalized paths, stale delete targets, lexical root escapes, and
|
|
75
|
+
symlink escapes fail closed; cross-file forbidden edges and cycles are reported before commit.
|
|
76
|
+
- **T03 optional architecture change map:** strict schema `1.0` describes canonical operations,
|
|
77
|
+
resolved layers, and local edges. CLI/MCP preflight binds its deterministic hash; no map is
|
|
78
|
+
installed by default. Both published schema subpaths are parity-checked with the Domain contract.
|
|
79
|
+
- **T04 honest structural convergence:** map-enabled preflight compares the explicit complete
|
|
80
|
+
candidate with the current supplied base through the shared analysis IR. Stable findings separate
|
|
81
|
+
satisfied, missing, contradictory, and unplanned file/edge work; structural drift rejects the
|
|
82
|
+
batch without writes, while every result states behavioral completion was not evaluated.
|
|
83
|
+
- **T05 actionable, context-independent enforcement:** blocking diagnostics expose one deterministic
|
|
84
|
+
`nextAction` across JSON and human output. Doctor and hook repair JSON separate supported,
|
|
85
|
+
installed, active, and bypassable enforcement with evidence and operation coverage; MCP-only and
|
|
86
|
+
locally unverifiable required-status state remain labeled honestly.
|
|
87
|
+
- **Complete-patch hook parity:** governed Codex `ApplyPatch` create/update/delete sets use the same
|
|
88
|
+
atomic preflight as CLI/MCP before per-file safety checks, catching batch-only edges and cycles.
|
|
89
|
+
Codex remains advisory/bypassable at the host level.
|
|
90
|
+
- **Fixed Phase T evaluation:** `npm run eval:change-integrity` proves identical no-context hashes and
|
|
91
|
+
verdicts, CLI/MCP/hook/final diagnostic parity, one concise casual denial, prewritten feature
|
|
92
|
+
acceptance, and strict Ark green without a live LLM or required planning file.
|
|
93
|
+
### Fixed
|
|
94
|
+
|
|
95
|
+
- **Compatibility/release:** analysis-result `1.1` preserves `1.0` TypeScript values; first-push
|
|
96
|
+
zero SHAs and resumable npm release assets are handled safely.
|
|
97
|
+
|
|
98
|
+
Release note: `docs/releases/3.1.0.md`.
|
|
8
99
|
|
|
9
100
|
## 3.0.5 — 2026-07-14
|
|
10
101
|
|
package/README.md
CHANGED
|
@@ -16,8 +16,9 @@ and makes sure a “green” check means something real.
|
|
|
16
16
|
|
|
17
17
|
</div>
|
|
18
18
|
|
|
19
|
-
> **ArkGate 3.0**
|
|
20
|
-
>
|
|
19
|
+
> **ArkGate 3.2.0** is current stable: contract health (advisory meta-lint of the contract +
|
|
20
|
+
> governance weight), on top of 3.1's policy-transition checks, atomic multi-file preflight, and
|
|
21
|
+
> optional structural convergence. [Release notes](docs/releases/3.2.0.md).
|
|
21
22
|
|
|
22
23
|
---
|
|
23
24
|
|
|
@@ -136,7 +137,7 @@ npx arkgate-check --install-agent-gates --force
|
|
|
136
137
|
npx arkgate-check --doctor
|
|
137
138
|
```
|
|
138
139
|
|
|
139
|
-
Full checklist (CI, MCP, Codex, imports): **[
|
|
140
|
+
Full checklist (CI, MCP, Codex, imports): **[migrate-from-ark-runtime-kernel.md](https://github.com/pedroknigge/arkgate/blob/main/docs/migrate-from-ark-runtime-kernel.md)**.
|
|
140
141
|
|
|
141
142
|
---
|
|
142
143
|
|
|
@@ -156,7 +157,7 @@ Aliases `ark` / `ark-check` / `ark-mcp` still work. **npm / pnpm / yarn**. No in
|
|
|
156
157
|
<details>
|
|
157
158
|
<summary>What <code>/ark-autopilot</code> does under the hood (optional detail)</summary>
|
|
158
159
|
|
|
159
|
-
1. Setup if needed (`ark start`
|
|
160
|
+
1. Setup if needed (`ark start` previews; review, then `ark start --apply`).
|
|
160
161
|
2. **Explore pass** (decision-grade map of *this* product; field path when demos exist).
|
|
161
162
|
3. **Dual plan:** **A** remediation from `--plan` (mechanical-safe only by default); **B** pattern/evolution bets (never auto-applied as mechanical-safe). Empty plan ≠ “healthy” without explore/B.
|
|
162
163
|
4. Apply A → re-check; judgment only when you ask for full apply.
|
|
@@ -199,6 +200,20 @@ constrain + validate + optional `autoPatch` + `judgmentBrief`). PreToolUse hooks
|
|
|
199
200
|
never silent write). Cursor/Codex MCP calls remain advisory. See
|
|
200
201
|
[docs/ai-gates.md](docs/ai-gates.md).
|
|
201
202
|
|
|
203
|
+
For a complete multi-file architecture-source candidate, use MCP **`ark_prepare_change`** or
|
|
204
|
+
`ark preflight --changes change-set.json --json`. Creates, updates, and deletes are evaluated as
|
|
205
|
+
one read-only graph, so an edge or cycle that appears only across the batch is rejected before any
|
|
206
|
+
project file is written. With `--change-map map.json` (or MCP `changeMap`), the same verdict also
|
|
207
|
+
classifies planned structure as satisfied, missing, contradictory, or unplanned. This is structural
|
|
208
|
+
convergence only: behavioral completion is always reported as not evaluated.
|
|
209
|
+
|
|
210
|
+
Every blocking diagnostic carries stable rule/location/evidence fields plus one deterministic
|
|
211
|
+
`nextAction`; human CLI/hook text prints that same action. A complete Codex `ApplyPatch` payload is
|
|
212
|
+
reconstructed and sent through the same atomic engine before per-file safety checks. Codex remains
|
|
213
|
+
honestly bypassable/advisory because not every Code Mode write dispatches the project hook. The
|
|
214
|
+
verdict depends only on the explicit contract and candidate—not `AGENTS.md`, skills, injected prose,
|
|
215
|
+
or an LLM.
|
|
216
|
+
|
|
202
217
|
| Need | Skill | Not |
|
|
203
218
|
|------|--------|-----|
|
|
204
219
|
| Only the apply loop for plan **A** (edges) | `/ark-loop` | empty A + design residual → explore |
|
|
@@ -229,6 +244,22 @@ Brownfield phases: **Align** (honest contract) → **Stabilize** (real baseline)
|
|
|
229
244
|
This table describes the supported profile **after its files are installed and the host loads/trusts them**. A hard local boundary covers only the listed hook operations; alternate tools, direct filesystem writes, and human edits still rely on CI. MCP validation is advisory because the agent must call it. The CI check blocks a merge only when the repository makes that status required. Repair payloads never write code silently: the host must re-inject the candidate and ArkGate revalidates it. Run `arkgate-check --doctor` for the evidence actually detected in the current repository.
|
|
230
245
|
<!-- arkgate-host-support:end -->
|
|
231
246
|
|
|
247
|
+
#### Why the hard guarantee lives at the merge gate
|
|
248
|
+
|
|
249
|
+
The split above is a deliberate trade-off, not a gap. ArkGate validates at the earliest boundary
|
|
250
|
+
each host offers and enforces at the earliest boundary a repository can make non-bypassable: the
|
|
251
|
+
required merge status. Hard hooks (Claude Code, Grok Build) deny the listed write operations at
|
|
252
|
+
write time; advisory surfaces (MCP, rules) coach the agent while it works. But any local boundary
|
|
253
|
+
can be routed around — another tool, a direct filesystem write, a human edit — so the only
|
|
254
|
+
guarantee ArkGate claims for every path is the `arkgate-check --strict-merge` check, and only when
|
|
255
|
+
the repository makes that status required. Local checks optimize feedback speed; the merge gate
|
|
256
|
+
owns correctness.
|
|
257
|
+
|
|
258
|
+
A useful consequence: the contract doubles as a pressure sensor. Recurring violations or baseline
|
|
259
|
+
exceptions concentrated on one layer edge are evidence that the current design stopped fitting the
|
|
260
|
+
code — a reason to reshape the contract deliberately (start with `/ark-explore`), never to weaken
|
|
261
|
+
the gate.
|
|
262
|
+
|
|
232
263
|
Detailed setup: [docs/ai-gates.md](docs/ai-gates.md).
|
|
233
264
|
|
|
234
265
|
---
|
|
@@ -245,22 +276,25 @@ ark.config.json
|
|
|
245
276
|
|
|
246
277
|
- **Presets:** hexagonal, layered, feature-sliced, monorepo, ui-surface, vertical-slice, ddd-bounded-contexts (+ aliases clean-architecture / onion-architecture). Layers start optional; doctor suggests tightening populated cores. Cross-slice / cross-context bans use optional `peerIsolation` rules.
|
|
247
278
|
- **Versioned config:** generated contracts include `$schema` + `schemaVersion`; CLI, MCP, and
|
|
248
|
-
ESLint validate through the same loader. Unknown keys fail with their JSON path.
|
|
249
|
-
|
|
279
|
+
ESLint validate through the same loader. Unknown keys fail with their JSON path. Strict merge
|
|
280
|
+
also compares the contract transition and blocks unacknowledged weakening with hashes and stable
|
|
281
|
+
finding ids. See the [configuration and editor guide](docs/configuration.md).
|
|
250
282
|
- **Frameworks:** Nest / Next / express / library layouts get sensible globs on init so day-one coverage is real.
|
|
251
283
|
- **Brownfield:** baseline ratchet, refuse to freeze a wrong contract, `/ark-adopt` for mature trees.
|
|
252
|
-
- **Agents:** `ark start`
|
|
284
|
+
- **Agents:** `ark start` previews one compact active-host router (≤5 files / 25 KB); `--apply`
|
|
285
|
+
writes those exact bytes. Full skills remain explicit via `--install-agent-gates --skills-only`;
|
|
286
|
+
reports remain opt-in via `ark-check --report`.
|
|
253
287
|
- **Write protocol (2.10 / Track W):** mechanical-safe **autoPatch** on the write gate (`import type`); MCP **`ark_prepare_write`** (place + validate + patch + judgmentBrief); opt-in hook **`--hook-repair`** (`ARK_REPAIR_JSON`); doctor **`writePath`** (repair vs reject-only); loop-cost eval (`npm run eval:loop-cost`). Port-proof inject is **judgment** (arity change), not silent auto-apply.
|
|
288
|
+
- **Enforcement ladder (Phase T):** doctor JSON exposes `writePath.enforcementLadder` with separate
|
|
289
|
+
`supported`, `installed`, `active`, `bypassable`, evidence, operation coverage, and required-status
|
|
290
|
+
honesty. Hook repair JSON carries the operation-scoped ladder; MCP alone remains advisory.
|
|
254
291
|
- **Fail-closed CI (2.11):** `--strict-merge` combines config coverage, shared gate-file
|
|
255
292
|
presence, and bypass diagnostics for dynamic imports, TypeScript suppressions, explicit `any`
|
|
256
293
|
casts, InMemory runtime defaults, and disabled peer isolation. `--strict` is a compatibility
|
|
257
294
|
alias. Neither requires an editor hook; use `--require-write-hook claude|grok` when that local
|
|
258
295
|
guarantee is part of the check.
|
|
259
|
-
- **
|
|
260
|
-
|
|
261
|
-
branch). The V05 beta-exit audit passed with 12 pinned public adoptions, 97% median governed
|
|
262
|
-
coverage, and zero P0/P1 findings. Stable publication remains the signed-tag, GitHub Release,
|
|
263
|
-
and provenance-backed npm workflow documented in [the 3.0.0 release notes](docs/releases/3.0.0.md).
|
|
296
|
+
- **Release evidence:** independent 3.0 audit baseline plus signed-tag, GitHub Release, and
|
|
297
|
+
provenance-backed npm publication; see the [3.1.0 release notes](docs/releases/3.1.0.md).
|
|
264
298
|
- **TypeScript:** project compilers 5.x / 6.x / 7.x — gate falls back to a nested JS-API TypeScript when TS 7’s main export is version-only ([docs/typescript-support.md](docs/typescript-support.md)).
|
|
265
299
|
|
|
266
300
|
### Why not only ESLint / dependency-cruiser / Nx?
|
|
@@ -288,12 +322,14 @@ npx arkgate start --tools codex --apply # select the host explicitly
|
|
|
288
322
|
npx arkgate start --install --apply # also add arkgate to package.json (explicit only)
|
|
289
323
|
npx arkgate start --remove-host codex # preview compact-host removal; add --apply to confirm
|
|
290
324
|
npx arkgate-check --doctor # health + Adoption gaps (not just fitness)
|
|
291
|
-
npx arkgate-check --doctor --json #
|
|
325
|
+
npx arkgate-check --doctor --json # adoption + explicit writePath.enforcementLadder
|
|
292
326
|
npx arkgate-check --strict # fail-closed CI + installed-gate/safety checks
|
|
293
327
|
npx arkgate-check --plan # safe-to-auto-fix vs your call
|
|
294
328
|
npx arkgate-check --coverage # Governed: N%
|
|
295
329
|
npx arkgate-check --report ark-report.html # showcase HTML (opens in browser on local TTY; --no-open to skip)
|
|
296
330
|
npx arkgate-check --baseline # only NEW violations fail
|
|
331
|
+
npx arkgate preflight --changes changes.json --json # atomic read-only batch verdict
|
|
332
|
+
npx arkgate preflight --changes changes.json --change-map map.json --json # intent hash + structural convergence
|
|
297
333
|
npx arkgate upgrade # package + gates/skills + MCP/Codex normalize
|
|
298
334
|
```
|
|
299
335
|
|
|
@@ -314,7 +350,7 @@ separate experimental package:
|
|
|
314
350
|
|
|
315
351
|
```ts
|
|
316
352
|
import { createStrictArkKernelFromConfig } from '@arkgate/runtime';
|
|
317
|
-
// see
|
|
353
|
+
// see the repository production-hardening and package-surface guides
|
|
318
354
|
```
|
|
319
355
|
|
|
320
356
|
The stable `arkgate` package does not bundle runtime implementation. The deprecated
|
|
@@ -328,7 +364,7 @@ The kernel’s default stores (`InMemoryEventBuffer`, `InMemoryAuditStore`,
|
|
|
328
364
|
`InMemoryReadModelStore`, `InMemoryWorkflowStore`) are **reference in-memory only**:
|
|
329
365
|
fine for tests, demos, and single-process local work — they **do not** survive restarts
|
|
330
366
|
and are **not** production durability. Implement the store interfaces (or inject your own)
|
|
331
|
-
for real systems. Details: [
|
|
367
|
+
for real systems. Details: [production-hardening.md](https://github.com/pedroknigge/arkgate/blob/main/docs/production-hardening.md).
|
|
332
368
|
|
|
333
369
|
---
|
|
334
370
|
|
|
@@ -337,16 +373,17 @@ for real systems. Details: [docs/production-hardening.md](docs/production-harden
|
|
|
337
373
|
| Audience | Link |
|
|
338
374
|
|----------|------|
|
|
339
375
|
| New builders (plain language) | [docs/enthusiast/](docs/enthusiast/README.md) |
|
|
340
|
-
| **Package surface
|
|
341
|
-
| Wire
|
|
376
|
+
| **Package surface and configuration** | [package policy](docs/package-surface.md) · [contract](docs/configuration.md) |
|
|
377
|
+
| Wire agents + **ESLint (CI-parity)** | [docs/ai-gates.md](docs/ai-gates.md) · [threat model](docs/threat-model.md) |
|
|
342
378
|
| **TypeScript 5 / 6 / 7 support** | [docs/typescript-support.md](docs/typescript-support.md) |
|
|
343
|
-
| Migrate from `ark-runtime-kernel` | [docs/migrate-from-ark-runtime-kernel.md](docs/migrate-from-ark-runtime-kernel.md) |
|
|
379
|
+
| Migrate from `ark-runtime-kernel` | [docs/migrate-from-ark-runtime-kernel.md](https://github.com/pedroknigge/arkgate/blob/main/docs/migrate-from-ark-runtime-kernel.md) |
|
|
344
380
|
| Messy existing repo | [docs/brownfield-adoption.md](docs/brownfield-adoption.md) |
|
|
345
381
|
| Agent / MCP tools | [docs/agent-guide.md](docs/agent-guide.md) |
|
|
382
|
+
| Security reporting | [SECURITY.md](SECURITY.md) |
|
|
346
383
|
| Demos | [docs/demos/](docs/demos/) |
|
|
347
384
|
| Examples | [examples/](examples/README.md) |
|
|
348
|
-
|
|
|
349
|
-
| Roadmap | [ROADMAP.md](ROADMAP.md) · [Changelog](CHANGELOG.md) |
|
|
385
|
+
| Latest release (3.1.0) | [release notes](docs/releases/3.1.0.md) · [3.0.0 baseline](docs/releases/3.0.0.md) |
|
|
386
|
+
| Roadmap and decisions | [ROADMAP.md](ROADMAP.md) · [ADRs](docs/adr/) · [Changelog](CHANGELOG.md) |
|
|
350
387
|
|
|
351
388
|
---
|
|
352
389
|
|
|
@@ -363,7 +400,7 @@ npm run check:architecture # Ark gates itself
|
|
|
363
400
|
**npm:** [`arkgate`](https://www.npmjs.com/package/arkgate) · formerly `ark-runtime-kernel`
|
|
364
401
|
**Product:** **ArkGate** — architecture co-pilot / gate for AI TypeScript (not a runtime kernel).
|
|
365
402
|
CLI: `arkgate` · `arkgate-check` · `arkgate-mcp` (aliases `ark` / `ark-check` / `ark-mcp` still work for one major).
|
|
366
|
-
MCP registry: `io.github.pedroknigge/arkgate
|
|
403
|
+
MCP registry: [`io.github.pedroknigge/arkgate`](https://registry.modelcontextprotocol.io/) (`server.json` @ package version).
|
|
367
404
|
**Source:** [github.com/pedroknigge/arkgate](https://github.com/pedroknigge/arkgate)
|
|
368
405
|
|
|
369
406
|
Node ≥ 18 · **MIT**.
|
package/bin/ark-check.mjs
CHANGED
|
@@ -99,6 +99,7 @@ import {
|
|
|
99
99
|
} from './lib/config-warnings.mjs';
|
|
100
100
|
import { runArchitectureScan } from './lib/architecture-scan.mjs';
|
|
101
101
|
import { validateHardWriteRequest } from './lib/enforcement-profiles.mjs';
|
|
102
|
+
import { analyzePolicyTransition } from './lib/policy-delta-io.mjs';
|
|
102
103
|
|
|
103
104
|
|
|
104
105
|
function parseArgs(argv) {
|
|
@@ -110,6 +111,7 @@ function parseArgs(argv) {
|
|
|
110
111
|
tsconfig: undefined,
|
|
111
112
|
json: false,
|
|
112
113
|
strictConfig: false,
|
|
114
|
+
strictMerge: false,
|
|
113
115
|
requireGates: false,
|
|
114
116
|
requireWriteHook: undefined,
|
|
115
117
|
init: false,
|
|
@@ -119,6 +121,9 @@ function parseArgs(argv) {
|
|
|
119
121
|
force: false,
|
|
120
122
|
skillsOnly: false,
|
|
121
123
|
baseline: undefined,
|
|
124
|
+
policyBase: undefined,
|
|
125
|
+
policyBaseRef: undefined,
|
|
126
|
+
policyAck: undefined,
|
|
122
127
|
updateBaseline: false,
|
|
123
128
|
noCache: false,
|
|
124
129
|
coverage: false,
|
|
@@ -149,6 +154,7 @@ function parseArgs(argv) {
|
|
|
149
154
|
else if (arg === '--strict' || arg === '--strict-merge') {
|
|
150
155
|
args.strictConfig = true;
|
|
151
156
|
args.requireGates = true;
|
|
157
|
+
args.strictMerge = true;
|
|
152
158
|
}
|
|
153
159
|
else if (arg === '--strict-config') args.strictConfig = true;
|
|
154
160
|
else if (arg === '--require-gates') args.requireGates = true;
|
|
@@ -205,6 +211,9 @@ function parseArgs(argv) {
|
|
|
205
211
|
const next = argv[i + 1];
|
|
206
212
|
args.baseline = next && !next.startsWith('-') ? argv[++i] : '.ark-baseline.json';
|
|
207
213
|
}
|
|
214
|
+
else if (arg === '--policy-base') args.policyBase = requireValue(arg, i++);
|
|
215
|
+
else if (arg === '--policy-base-ref') args.policyBaseRef = requireValue(arg, i++);
|
|
216
|
+
else if (arg === '--policy-ack') args.policyAck = requireValue(arg, i++);
|
|
208
217
|
else if (arg === '--root') args.root = path.resolve(requireValue(arg, i++));
|
|
209
218
|
else if (arg === '--config') args.config = requireValue(arg, i++);
|
|
210
219
|
else if (arg === '--manifest') args.manifest = requireValue(arg, i++);
|
|
@@ -230,7 +239,7 @@ function usage() {
|
|
|
230
239
|
return [
|
|
231
240
|
'Usage: arkgate-check | ark-check (identical bins; product name ArkGate)',
|
|
232
241
|
' ark-check --version',
|
|
233
|
-
' ark-check --root <project> --config <ark.config.json> [--manifest <ark.manifest.json>] [--tsconfig <tsconfig.json>] [--strict-merge | --strict | --strict-config] [--require-gates] [--require-write-hook <host>] [--json] [--baseline [file]] [--report [file.html]] [--no-cache]',
|
|
242
|
+
' ark-check --root <project> --config <ark.config.json> [--manifest <ark.manifest.json>] [--tsconfig <tsconfig.json>] [--strict-merge | --strict | --strict-config] [--policy-base <file> | --policy-base-ref <git-ref>] [--policy-ack <file>] [--require-gates] [--require-write-hook <host>] [--json] [--baseline [file]] [--report [file.html]] [--no-cache]',
|
|
234
243
|
' ark-check --coverage [--json] per-layer file counts + full unclassified list (report only, exit 0)',
|
|
235
244
|
' ark-check --plan [--json] classified remediation plan (mechanical-safe / judgment / deferred) + goal; report only',
|
|
236
245
|
' ark-check --recommend [--json] [--write-plan] application-shape plan; --write-plan emits ark-adoption-plan.json',
|
|
@@ -287,6 +296,10 @@ function usage() {
|
|
|
287
296
|
'Use --strict-merge for the fail-closed CI profile: --strict-config + --require-gates',
|
|
288
297
|
'plus the security diagnostics surfaced by doctor. --strict is a compatibility alias.',
|
|
289
298
|
'This merge profile never depends on an editor/agent hook.',
|
|
299
|
+
'When a Git merge base is available, --strict-merge classifies the ark.config.json',
|
|
300
|
+
'transition. Weakening or judgment-required findings fail unless --policy-ack names',
|
|
301
|
+
'every finding and is bound to both policy hashes. Use --policy-base/--policy-base-ref',
|
|
302
|
+
'for an explicit comparison; ARK_POLICY_BASE_REF is the CI environment equivalent.',
|
|
290
303
|
'Add --require-write-hook claude|grok to validate a hard local write boundary for that',
|
|
291
304
|
'specific host. Cursor and Codex expose advisory MCP tools plus the shared CI check;',
|
|
292
305
|
'merge blocking requires repository policy to make that status required.',
|
|
@@ -1060,6 +1073,15 @@ async function main() {
|
|
|
1060
1073
|
|
|
1061
1074
|
const root = args.root;
|
|
1062
1075
|
const config = readConfig(root, args.config);
|
|
1076
|
+
const policyDelta = analyzePolicyTransition({
|
|
1077
|
+
root,
|
|
1078
|
+
configPath: args.config,
|
|
1079
|
+
candidateConfig: config,
|
|
1080
|
+
strictMerge: args.strictMerge,
|
|
1081
|
+
basePath: args.policyBase,
|
|
1082
|
+
baseRef: args.policyBaseRef,
|
|
1083
|
+
acknowledgementPath: args.policyAck,
|
|
1084
|
+
});
|
|
1063
1085
|
const manifest = readManifest(root, args.manifest);
|
|
1064
1086
|
const rules = manifest?.architecture?.rules ?? config.rules;
|
|
1065
1087
|
const files = collectGovernedFiles(root, config);
|
|
@@ -1216,7 +1238,9 @@ async function main() {
|
|
|
1216
1238
|
// Soft/advisory warnings (failsStrict === false) never fail --strict-config.
|
|
1217
1239
|
const strictWarnings = warnings.filter((w) => w.failsStrict !== false);
|
|
1218
1240
|
const ok =
|
|
1219
|
-
activeViolations.length === 0 &&
|
|
1241
|
+
activeViolations.length === 0 &&
|
|
1242
|
+
(!args.strictConfig || strictWarnings.length === 0) &&
|
|
1243
|
+
(policyDelta?.valid ?? true);
|
|
1220
1244
|
|
|
1221
1245
|
if (args.plan) {
|
|
1222
1246
|
const cov = computeCoverage(root, config, files, rules);
|
|
@@ -1384,6 +1408,7 @@ async function main() {
|
|
|
1384
1408
|
}
|
|
1385
1409
|
: {}),
|
|
1386
1410
|
...(codexRepoSkillGap ? { codexRepoSkillGap } : {}),
|
|
1411
|
+
...(policyDelta ? { policyDelta } : {}),
|
|
1387
1412
|
}, null, 2));
|
|
1388
1413
|
} else {
|
|
1389
1414
|
for (const warning of warnings) {
|
|
@@ -1402,7 +1427,22 @@ async function main() {
|
|
|
1402
1427
|
)
|
|
1403
1428
|
);
|
|
1404
1429
|
}
|
|
1405
|
-
if (
|
|
1430
|
+
if (policyDelta && !policyDelta.valid) {
|
|
1431
|
+
for (const finding of policyDelta.findings.filter(
|
|
1432
|
+
({ classification }) =>
|
|
1433
|
+
classification === 'weakening' || classification === 'judgment-required'
|
|
1434
|
+
)) {
|
|
1435
|
+
console.error(
|
|
1436
|
+
`${color.red('policy')} ${finding.classification} ${finding.path}: ${finding.message}`
|
|
1437
|
+
);
|
|
1438
|
+
console.error(` Next: ${finding.nextAction}`);
|
|
1439
|
+
}
|
|
1440
|
+
console.error(
|
|
1441
|
+
`Policy transition blocked (${policyDelta.basePolicyHash} → ${policyDelta.candidatePolicyHash}). ` +
|
|
1442
|
+
'Provide --policy-ack with the exact hashes, finding ids, and a non-empty reason.'
|
|
1443
|
+
);
|
|
1444
|
+
}
|
|
1445
|
+
if (activeViolations.length === 0 && (policyDelta?.valid ?? true)) {
|
|
1406
1446
|
const advisoryOnly = warnings.length > 0 && strictWarnings.length === 0;
|
|
1407
1447
|
if (warnings.length === 0) {
|
|
1408
1448
|
console.log(`${color.green('✔')} Ark check passed.${baselineNote}`);
|
|
@@ -1421,7 +1461,9 @@ async function main() {
|
|
|
1421
1461
|
}
|
|
1422
1462
|
} else {
|
|
1423
1463
|
console.error(
|
|
1424
|
-
|
|
1464
|
+
activeViolations.length > 0
|
|
1465
|
+
? `${color.red('✖')} ${activeViolations.length} violation(s).${baselineNote}`
|
|
1466
|
+
: `${color.red('✖')} Policy transition rejected.${baselineNote}`
|
|
1425
1467
|
);
|
|
1426
1468
|
}
|
|
1427
1469
|
|