arkgate 3.6.1 → 3.8.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 (83) hide show
  1. package/CHANGELOG.md +122 -1145
  2. package/README.md +59 -19
  3. package/bin/ark-check-runtime.mjs +1598 -0
  4. package/bin/ark-check.mjs +32 -1565
  5. package/bin/ark-layer-match.mjs +2 -1
  6. package/bin/ark-mcp-runtime.mjs +1976 -0
  7. package/bin/ark-mcp.mjs +84 -1495
  8. package/bin/ark-shared.mjs +34 -38
  9. package/bin/ark.mjs +33 -66
  10. package/bin/lib/adapter-contract.mjs +161 -9
  11. package/bin/lib/agent-gates.mjs +1 -0
  12. package/bin/lib/analysis-completeness.mjs +28 -0
  13. package/bin/lib/analysis-engine.mjs +8 -8
  14. package/bin/lib/analysis-policy.mjs +27 -0
  15. package/bin/lib/architecture-scan.mjs +70 -304
  16. package/bin/lib/auto-patch.mjs +76 -8
  17. package/bin/lib/ci-and-commands.mjs +1 -1
  18. package/bin/lib/codex-home.mjs +43 -16
  19. package/bin/lib/design-delta.mjs +4 -0
  20. package/bin/lib/design-smells.mjs +67 -14
  21. package/bin/lib/doctor-advisories.mjs +23 -7
  22. package/bin/lib/doctor-plan.mjs +44 -47
  23. package/bin/lib/enforcement-state.mjs +2 -0
  24. package/bin/lib/github-enforcement.mjs +443 -0
  25. package/bin/lib/hook-templates.mjs +12 -148
  26. package/bin/lib/html-report-advisories.mjs +59 -0
  27. package/bin/lib/html-report-depth.mjs +9 -0
  28. package/bin/lib/html-report.mjs +5 -5
  29. package/bin/lib/install-migrate.mjs +83 -79
  30. package/bin/lib/managed-upgrade.mjs +622 -0
  31. package/bin/lib/mcp-adoption.mjs +3 -1
  32. package/bin/lib/parse-health.mjs +75 -0
  33. package/bin/lib/port-proof.mjs +2 -2
  34. package/bin/lib/prepare-change.mjs +68 -38
  35. package/bin/lib/prepare-write.mjs +7 -1
  36. package/bin/lib/reshape-decisions.mjs +284 -0
  37. package/bin/lib/resident-doctor-client.mjs +55 -0
  38. package/bin/lib/resident-hook.mjs +247 -0
  39. package/bin/lib/resolved-candidate-facts.mjs +1160 -0
  40. package/bin/lib/scan-files.mjs +19 -6
  41. package/bin/lib/snippet-analysis.mjs +119 -0
  42. package/bin/lib/source-policy.mjs +24 -0
  43. package/bin/lib/typescript-host.mjs +15 -18
  44. package/bin/lib/unavailable-analysis.mjs +76 -0
  45. package/bin/lib/upgrade-command.mjs +115 -0
  46. package/bin/lib/weakest-link.mjs +21 -179
  47. package/bin/lib/write-path-capabilities.mjs +167 -16
  48. package/bin/lib/write-path-detect.mjs +3 -2
  49. package/dist/eslint/index.cjs +3 -3
  50. package/dist/eslint/index.d.ts +3 -0
  51. package/dist/eslint/index.js +3 -3
  52. package/dist/index.cjs +7 -7
  53. package/dist/index.d.ts +1073 -141
  54. package/dist/index.js +7 -7
  55. package/docs/agent-guide.md +127 -52
  56. package/docs/ai-gates.md +100 -18
  57. package/docs/configuration.md +6 -0
  58. package/docs/demos/01-write-gate-self-correction.md +2 -2
  59. package/docs/enthusiast/README.md +10 -10
  60. package/docs/enthusiast/how-to-gallery-starter.md +2 -2
  61. package/docs/enthusiast/reference-commands.md +18 -1
  62. package/docs/enthusiast/tutorial-first-project.md +2 -2
  63. package/docs/package-surface.md +101 -14
  64. package/docs/typescript-support.md +118 -37
  65. package/package.json +33 -4
  66. package/schemas/ark.analysis-result.schema.json +159 -2
  67. package/schemas/ark.design-delta.schema.json +1 -0
  68. package/schemas/ark.enforcement-state.schema.json +84 -0
  69. package/schemas/ark.resolved-candidate-facts.schema.json +1 -0
  70. package/server.json +2 -2
  71. package/templates/skills/ark-autopilot.md +12 -0
  72. package/templates/skills/ark-explore.md +12 -5
  73. package/templates/skills/ark-fix.md +12 -2
  74. package/templates/skills/ark-loop.md +14 -1
  75. package/templates/skills/ark-runtime.md +15 -8
  76. package/templates/skills/ark-upgrade.md +122 -182
  77. package/bin/lib/ai-velocity.mjs +0 -293
  78. package/bin/lib/graph-cycles.mjs +0 -6
  79. package/bin/lib/safety-diagnostics.mjs +0 -284
  80. package/bin/lib/ts-resolve.mjs +0 -227
  81. package/dist/configTypes-DAPvBqK6.d.cts +0 -61
  82. package/dist/eslint/index.d.cts +0 -146
  83. package/dist/index.d.cts +0 -986
@@ -8,8 +8,10 @@ hard-CI split is a deliberate trade-off, not a gap: local hooks and MCP coach at
8
8
  while a required merge status is the one boundary a repository can make every write path share.
9
9
 
10
10
  CLI names: prefer **`arkgate` / `arkgate-check` / `arkgate-mcp`**; aliases `ark` / `ark-check` /
11
- `ark-mcp` still work for one major. TypeScript **5.x / 6.x / 7.x** as the project compiler:
12
- see [typescript-support.md](typescript-support.md).
11
+ `ark-mcp` still work for one major. The current source candidate tests packed project TypeScript
12
+ **5.9.3 / 6.0.3 / 7.0.2** and uses an exact, physically distinct TypeScript 6 analysis host when
13
+ the project API is unusable. Published 3.7.0 predates that correction; see the distribution and
14
+ completeness boundary in [typescript-support.md](typescript-support.md).
13
15
 
14
16
  ## Architecture playbook and `ark-check --recommend`
15
17
 
@@ -65,6 +67,7 @@ npx ark init --archetype crud-product --yes # non-interactive: shape → prese
65
67
  npx ark init # TTY wizard: pick application shape (1–8), not a framework
66
68
  npx ark-check --doctor # includes "New here?" when coverage is low or config is fresh
67
69
  npx ark-check --report beginner.html --beginner # simplified HTML for enthusiasts
70
+ npx ark-check --ratchet-cores # require populated core layers after raw graph is green
68
71
  npx ark-check --watch # debounced re-check when governed files change
69
72
  ```
70
73
 
@@ -73,6 +76,14 @@ docs or CI templates. Compact `ark start` previews first and keeps the applied s
73
76
  project files and 25 KB;
74
77
  run `ark-check --report ark-report.html` explicitly when you want to establish an origin/evolution
75
78
  baseline. Do not `--reset-origin` unless the user explicitly wants a new baseline.
79
+ `ark-check --report --no-archive` still creates `origin.*` on the first report (or on an explicit
80
+ reset) and refreshes `latest.*`; it skips only the timestamped JSON file under
81
+ `.ark/reports/history/`.
82
+
83
+ Once the **raw** graph has zero violations (the baseline is deliberately ignored) and governed
84
+ coverage is at least 50%, `ark-check --ratchet-cores` changes `optional: true` to
85
+ `optional: false` for populated core layers in `ark.config.json`. Empty cores remain optional.
86
+ The command refuses active raw violations or low coverage; re-run `ark-check --doctor` after it.
76
87
 
77
88
  To remove a compact host integration, preview `ark start --remove-host <host>` and add `--apply`
78
89
  only after review. Ark removes only its exact compact artifacts, leaves customized files untouched
@@ -90,6 +101,7 @@ explore then apply A + propose/apply-with-ok B. `/ark-loop` = plan A only. Empty
90
101
  ```bash
91
102
  npx ark-check --doctor --json # designFitness, designSmells[].outcome, postGreenPath, goldenPattern, pilotLoop
92
103
  npx ark-check --plan --json # plan.goal.designWeak + plan.patternBets[] + plan.pilotLoop
104
+ npx ark-check --doctor --fail-on-new-smells --base-ref origin/main --json # opt-in new/worsened design delta
93
105
  ```
94
106
 
95
107
  **Post-green path (Q01):** when design-weak, doctor sets `postGreenPath` / `primaryNextAction`
@@ -104,7 +116,8 @@ Never multi-pilot batch; never mechanical-safe; never claim healthy finished whi
104
116
  **AI-velocity evidence (Q05):** deterministic fixture bench (no live LLM) compares the same
105
117
  feature add on design-weak vs golden-path trees. Run `npm run eval:ai-velocity`; metric is
106
118
  `placementTurns` (agent-equivalent steps to the DomainModel home). Method is stored next to
107
- the number in `eval/ai-velocity-report.json`. See [eval/README.md](../eval/README.md).
119
+ the number in `eval/ai-velocity-report.json`. See
120
+ [the evaluation guide](https://github.com/pedroknigge/arkgate/blob/main/eval/README.md).
108
121
 
109
122
  Smell **ids** (stable JSON) plus **outcome** lines (plain language, Q02) on each
110
123
  `designSmells[]` object — prefer `outcome` for humans; keep `id` for automation:
@@ -112,7 +125,7 @@ Smell **ids** (stable JSON) plus **outcome** lines (plain language, Q02) on each
112
125
  | id | Outcome (what to do / why the AI struggles) |
113
126
  |----|-----------------------------------------------|
114
127
  | `io-under-application` | Business code reaches DB/APIs directly — put I/O behind a port/adapter |
115
- | `handler-in-persistence` | HTTP handlers under storage folders — move handlers to API/UI |
128
+ | `handler-in-persistence` | Static framework HTTP imports (`next/server`), `defineRoute` calls, or handler bodies under Persistence-role storage folders — move transport to API/UI |
116
129
  | `god-module` | Huge multi-job files — split the pilot by concern |
117
130
  | `domain-logic-in-ui` | can*/calculate* in UI — move pure rules into Domain |
118
131
  | `facade-sql-in-routes` | Routes import ORM/SQL — keep queries in repository/adapter |
@@ -138,12 +151,14 @@ migration acks a date so they cannot fossilize. X05 — acks matching no detecte
138
151
  as `ackLifecycle.stale`: fix the edge string or delete the entry. X06 — the family-infra
139
152
  carve-out also matches mid-name families (`HoursPersistenceAdapters -> PersistenceInfrastructure`).
140
153
 
141
- **Effect capabilities (U03, evidence-only):** the analysis IR reports typed capability uses for
142
- seven closed ids (`network`, `filesystem`, `clock`, `randomness`, `environment`, `process`,
143
- `persistence`). `collectCapabilityUses(ts, sourceFile)` is the symbol-aware collector (ambient
144
- globals + imports, one scanner shadowing/type-only/`globalThis` handled); `ir.capabilityUses`
145
- carries the import-based subset the pure engine can prove from content alone. Direct evidence
146
- only. **Walls (U04) are opt-in:** a layer with `capabilities: { deny: ["clock", …] }` or
154
+ **Effect capabilities (U03, evidence-only):** the public analysis IR reports typed capability
155
+ uses for seven closed ids (`network`, `filesystem`, `clock`, `randomness`, `environment`,
156
+ `process`, `persistence`) through `analyzeProject(...).ir.capabilityUses`. The CLI/hook adapters
157
+ add symbol-aware ambient evidence internally (shadowing/type-only/`globalThis` handled); the
158
+ pure IR carries the import-based subset it can prove from content alone. `collectCapabilityUses`
159
+ and `CAPABILITY_IDS` are internal implementation exports, not exports from `arkgate`; the related
160
+ public low-level root helper is `collectForbiddenCapabilityUses`. Direct evidence only.
161
+ **Walls (U04) are opt-in:** a layer with `capabilities: { deny: ["clock", …] }` or
147
162
  `pure: true` (deny all seven) turns matching evidence into judgment-class
148
163
  `CAPABILITY_VIOLATION` findings with a port-injection `nextAction`; absence changes no verdict.
149
164
  One violation, one voice: ambient uses covered by `forbiddenGlobals` stay `FORBIDDEN_GLOBAL`.
@@ -164,6 +179,29 @@ never move. `reshapePilot.nextPilot` is a **proposed** one-at-a-time card (`move
164
179
  write gate + atomic preflight; merges are `/ark-architect` judgment cards. `notAScore`, never a
165
180
  verdict/`designFitness` input; there is no apply path.
166
181
 
182
+ **Reshape decision memory (Y01):** when the team accepts, defers, or rejects that target, record
183
+ the explicit verdict in `.ark/reshape-decisions.json` using the card's exact
184
+ `decisionTarget` (`concept` + complete sorted `anchors`), a non-empty `reason`, and optional
185
+ `reviewBy` (`YYYY-MM-DD`). Current rejected/deferred decisions hide only the repeated pilot card;
186
+ the physical facts keep rendering. Accepted keeps the same `/ark-loop` path. Expired/malformed
187
+ dates and decisions whose anchor set changed no longer apply; doctor/report list them. The golden
188
+ pattern is never parsed to infer a decision — cite it in `reason` when it explains the layout.
189
+
190
+ ```json
191
+ {
192
+ "schemaVersion": "1",
193
+ "decisions": [
194
+ {
195
+ "concept": "projects",
196
+ "anchors": ["src/app/api", "src/lib/api-handlers", "src/lib/repositories"],
197
+ "verdict": "rejected",
198
+ "reason": "These role directories are our thin-shell-handlers-data golden layout.",
199
+ "reviewBy": "2027-01-31"
200
+ }
201
+ ]
202
+ }
203
+ ```
204
+
167
205
  **Governance weight (W02):** `contractHealth.governanceWeight` reports raw facts (layers, rules,
168
206
  governed files, files/layer, rules/layer) plus a fixed band (`heavy` / `typical` / `light` /
169
207
  `unknown`) with fixed wording. It is explicitly `notAScore` — never a gate input. Read `heavy` as
@@ -179,7 +217,8 @@ persisted as a short Shape plan under the repo; not a gate requirement.
179
217
  **Full-skill agent co-pilot:** after explicitly installing the `/ark-*` pack, use
180
218
  `/ark-autopilot` (explore-first, dual plan A remediation + B pattern bets). Recon without
181
219
  applying: `/ark-explore`. The default compact router uses MCP/CLI directly. Never treat empty
182
- `--plan` steps as “architecture healthy” when `designWeak` / non-empty `patternBets` remain.
220
+ `--plan` steps as “architecture healthy” when `designWeak` / non-empty `patternBets` remain, or
221
+ when `plan.completeness !== "complete"`. Partial and unavailable analysis force `goal.met: false`.
183
222
 
184
223
  `ark init --archetype <id>` maps playbook ids to named presets (`hexagonal`, `layered`,
185
224
  `feature-sliced`, `monorepo`). With `--yes` and no archetype, Ark auto-selects from
@@ -337,11 +376,18 @@ Prefer preparing the write before the host commits it to disk:
337
376
  | MCP **`ark_prepare_write`** | Place + constrain + validate + optional `autoPatch` + `judgmentBrief` + contentHash + optional `goldenPattern` in one call |
338
377
  | MCP **`ark_prepare_change`** | Validate one complete create/update/delete batch in memory; optional `changeMap` also returns structural convergence; never writes |
339
378
  | CLI **`ark preflight --changes <file> --json`** | Same atomic verdict and map convergence for hosts/scripts that do not call MCP |
340
- | Write-gate **`autoPatch`** | Mechanical-safe **import type** rewrites only; post-patch revalidation green or discarded |
379
+ | Write-gate **`autoPatch`** | Mechanical-safe **import type** rewrites only; post-patch lexical validation must pass or the patch is discarded. It remains `partial`/non-green until complete-candidate preflight. |
341
380
  | PreToolUse **`--hook-repair`** | On deny: `ARK_REPAIR_JSON` / `ARK_AUTOPATCH_JSON` on stderr (still exit 2 — never silent write) |
342
- | Doctor **`writePath`** | Reports installed mode plus `enforcementLadder` (`supported` / `installed` / `active` / `bypassable`, evidence, operation coverage, required-status honesty) |
381
+ | Opt-in design delta | `--fail-on-new-smells --base-ref <ref>` blocks only new/worsened supported smells; missing base fails closed; schema: `arkgate/schema/design-delta` |
382
+ | Doctor **`writePath`** | Schema-backed support/assets/runtime/operation/bypass/required/`hard` evidence; only fresh covered-operation proof permits `hard:true` |
343
383
  | Doctor **`goldenPattern`** | Optional Q03 advisory summary (`present` / `invalid`); never clears design-weak |
344
384
 
385
+ **Published 3.7.0 limitation:** its compiler-free atomic graph can miss aliases/workspace edges.
386
+ The current source candidate closes that divergence through versioned resolved-candidate facts;
387
+ API, bundle, CLI, MCP, complete-patch hook, and final strict check share the same candidate evidence.
388
+ Lexical/single-snippet feedback remains explicitly partial and non-green. The normal strict gate is
389
+ still the required final merge boundary.
390
+
345
391
  Port-proof inject binding is **judgment** for auto-apply (signature/arity change), not write-path autoPatch.
346
392
  Full reference: [ai-gates.md](ai-gates.md). Loop-cost harness: `npm run eval:loop-cost`.
347
393
 
@@ -372,7 +418,18 @@ npx arkgate-check --install-agent-gates --tools claude,cursor,codex,grok
372
418
  | **Grok Build** | `.grok/hooks/ark-write-gate.json` + `.grok/config.toml` / `.mcp.json` | `.grok/skills/<name>/SKILL.md` |
373
419
 
374
420
  This is a path reference, not a guarantee table. Full copy-paste setups:
375
- [ai-gates.md](ai-gates.md). Skill inventory: main [README](../README.md#agent-skills-ark-).
421
+ [ai-gates.md](ai-gates.md). Skill inventory: main
422
+ [README](../README.md#other-skills-only-when-you-need-them).
423
+
424
+ For an optional executable adoption check, copy the shipped template into a Vitest/Jest suite
425
+ after installing ArkGate:
426
+
427
+ ```bash
428
+ mkdir -p tests
429
+ cp node_modules/arkgate/templates/tests/ark-adoption-gaps.test.ts tests/ark-adoption-gaps.test.ts
430
+ ```
431
+
432
+ It checks real on-disk contract, MCP, skill, and report artifacts; it does not mock the gate.
376
433
 
377
434
  ## Experimental runtime: contract discovery
378
435
 
@@ -396,7 +453,11 @@ const contract = ark.manifest().toJSON();
396
453
  ```
397
454
 
398
455
  Use `@arkgate/runtime` only when evaluating the experimental kernel. The stable `arkgate` gate
399
- package contains no runtime implementation. Package surface policy: [package-surface.md](package-surface.md).
456
+ package contains no runtime implementation. The companion is not currently present in the npm
457
+ registry and is not published by the root release workflow. Verify availability with
458
+ `npm view @arkgate/runtime dist-tags --json`; until a separate experimental publication exists,
459
+ evaluate it only from a source checkout after `npm run build:runtime` and install the local
460
+ `packages/runtime` folder. Package surface policy: [package-surface.md](package-surface.md).
400
461
 
401
462
  Agents should read `contract` and `ark.observability.report()` before generating or modifying code.
402
463
 
@@ -480,7 +541,8 @@ contract, Ark records `interceptor.error` and keeps delivering the original even
480
541
 
481
542
  ## Code Generation Validation
482
543
 
483
- Use `createAICodeGate()` before merging agent-generated source snippets:
544
+ Use `createAICodeGate()` for early lexical feedback on agent-generated source snippets, then run
545
+ complete-candidate preflight before merging:
484
546
 
485
547
  ```ts
486
548
  import * as ts from 'typescript';
@@ -498,11 +560,13 @@ const result = gate.validate(generatedSource, {
498
560
  agentId: 'agent-1',
499
561
  layer: 'DomainModel',
500
562
  });
501
- if (!result.valid) {
563
+ if (!result.lexicalValid) {
502
564
  for (const v of result.violations) {
503
565
  console.log(v.code, v.message, v.suggestion);
504
566
  }
505
567
  }
568
+ // result.valid remains false: call ark_prepare_change / preflightResolvedChange,
569
+ // then run the final strict repository check.
506
570
  ```
507
571
 
508
572
  Passing the `typescript` module enables built-in AST/symbol checks for dependencies, forbidden
@@ -617,25 +681,17 @@ Example config:
617
681
  }
618
682
  ```
619
683
 
620
- `ark-check` resolves imports through the TypeScript module resolver against your
621
- `tsconfig.json` relative, path-alias (e.g. `@infra/db`), package/workspace imports,
622
- TypeScript `import = require()`, dynamic `import()`, and `require()` — plus string intent
623
- references. It also flags raw
624
- `publish()` calls, publish calls without `metadata.source`, and source intent literals
625
- whose resolved layer differs from the publishing file layer. Pass `--tsconfig <path>` to force one config
626
- for every file; otherwise each source file uses the nearest `tsconfig.json` above it (like
627
- `tsc`), so monorepos with per-package alias maps work under a single `--root`. It resolves
628
- modules the way your build does, but is intentionally not yet a full type-graph analyzer
629
- (cross-layer type-only references beyond the import specifier are out of scope).
630
-
631
- Repeat runs are cached in `node_modules/.cache/ark-check.json` — unchanged files skip the
632
- parse, while import edges always re-resolve against the live filesystem so the cache can
633
- never hide a new violation. `--no-cache` disables it.
634
-
635
- `ark-check --json` also reports `warnings` for incomplete governance coverage: missing
636
- layers, unclassified included files, unmatched layer patterns, duplicate layers, and rules
637
- that reference unknown layers. These are advisory by default. Use `--strict-config` once a
638
- project is ready to fail CI on coverage gaps.
684
+ `ark-check` resolves relative, alias, package/workspace, `import =`, `import()` and `require()` edges
685
+ plus intent/publish evidence. It uses the nearest `tsconfig.json` unless `--tsconfig` is set;
686
+ importless type references are out.
687
+
688
+ Each run parses the full candidate and ignores retired `.cache/ark-check.json`; `--no-cache` is a
689
+ no-op. Z07 owns the identity-keyed snapshot after exact cold/warm parity.
690
+
691
+ Doctor JSON gives parse totals, deterministic top 12 and overflow. `partial` forces
692
+ `goal.met`/`valid`/`ok` false and strict exit `1`; unavailable exits `2`. Non-strict is advisory.
693
+
694
+ Config warnings stay advisory unless CI opts into `--strict-config`.
639
695
 
640
696
  Use the optional ESLint plugin for fast local feedback aligned with CI:
641
697
 
@@ -647,9 +703,11 @@ export default [
647
703
  ];
648
704
  ```
649
705
 
650
- Rules: `ark/no-domain-infra-imports` (layer edges from `ark.config.json`, same semantics as
651
- `arkgate-check`), `ark/no-forbidden-globals` (per-layer `forbiddenGlobals`),
652
- `ark/no-raw-event-publish`, and `ark/require-publish-source`. See [ai-gates.md](ai-gates.md).
706
+ Rules: `ark/no-domain-infra-imports` (exact parity for on-disk, in-scope static relative
707
+ imports/exports; resolved CLI/preflight is authoritative outside that envelope),
708
+ `ark/no-forbidden-globals` (per-layer `forbiddenGlobals`),
709
+ `ark/no-denied-capabilities` (per-layer capability deny sets), `ark/no-raw-event-publish`, and
710
+ `ark/require-publish-source`. See [ai-gates.md](ai-gates.md).
653
711
 
654
712
  ## Runtime Observability
655
713
 
@@ -729,8 +787,8 @@ not replace your web framework, HTTP clients, or job scheduler.
729
787
  ## Write-Path Gate (MCP)
730
788
 
731
789
  The strongest place to constrain an AI agent is the moment it writes a file, not after.
732
- `arkgate-mcp` / `ark-mcp` exposes ArkGate over MCP (JSON-RPC over stdio; gate host needs a
733
- JS-API TypeScript nested or project) so a host can gate
790
+ `arkgate-mcp` / `ark-mcp` exposes ArkGate over MCP (JSON-RPC over stdio; it prefers a usable
791
+ project TypeScript API, then exact `typescript-ark-host@6.0.3`) so a host can gate
734
792
  the write path:
735
793
 
736
794
  For a complete multi-file candidate, use `ark preflight --changes changes.json --json` or MCP
@@ -744,15 +802,32 @@ required, and `behavioralCompletion` remains `not-evaluated` even when structure
744
802
  npx ark-mcp --root . --config ark.config.json [--manifest ark.manifest.json]
745
803
  ```
746
804
 
747
- - **Resource `ark://manifest`** — contract discovery. Serve your exported
748
- `ark.manifest().toJSON()` via `--manifest`, or omit it to get the 11-layer profile
749
- (layers + rules) as the default contract.
750
- - **Tool `ark_recommend`** no args. Returns the deterministic application-shape plan
751
- (archetype, preset, phased adoption, analogy). Same as `ark-check --recommend --json`.
752
- - **Tool `validate_code`** args `{ source, layer?, filePath? }`. Runs `createAICodeGate`
753
- against the profile and (when a manifest is provided) the registered intent allowlist.
754
- Returns `{ valid, violations, layer }`; `isError` is `true` when invalid. If `layer` is
755
- omitted it is inferred from `filePath` via the config's layer patterns.
805
+ - **Resource `ark://manifest`** — contract discovery. Serve an exported
806
+ `ark.manifest().toJSON()` via `--manifest`. Without that flag, the resource uses every active
807
+ layer and the effective rules from `ark.config.json`; the strict 11-layer profile is the
808
+ fallback only when the project config declares no layers.
809
+
810
+ The server exposes these nine tools:
811
+
812
+ | Tool | Primary input and purpose |
813
+ |------|---------------------------|
814
+ | `validate_code` | `{ source, layer?, filePath? }`: validate one snippet; infer the layer from `filePath` when possible; return an error result when invalid. |
815
+ | `ark_check` | `{ strict?, baseline? }`: run the full project architecture check with structured diagnostics. |
816
+ | `ark_policy_delta` | `{ baseConfig, candidateConfig?, acknowledgement? }`: classify a complete contract transition; never edits the contract. |
817
+ | `ark_coverage` | No args: report per-layer counts, every unclassified file, unmatched layers, and missing rule edges. |
818
+ | `ark_place` | `{ filePath?, description? }`: resolve or propose a governed home and return its import/global constraints. |
819
+ | `ark_prepare_write` | `{ source, filePath?, description?, layer? }`: compose placement and snippet validation, with hashes and a mechanical-safe patch when available. |
820
+ | `ark_prepare_change` | `{ changes, changeMap? }`: preflight one complete create/update/delete batch in memory; never writes files. |
821
+ | `ark_recommend` | No args: return the deterministic application-shape plan used by `ark-check --recommend --json`. |
822
+ | `ark_suggest_include` | No args: propose TypeScript/JavaScript include roots from workspaces and nested packages. |
823
+
824
+ Current diagnostic envelopes use schema `1.3` and require `mode`,
825
+ `completeness: "complete" | "partial" | "unavailable"`, and structured
826
+ `completenessReasons`. Resolved results expose `policyHash`, `resolverIdentity`, `factsHash`, and
827
+ `candidateTreeHash`; MCP `ark_check` mirrors CLI `ok`. Single-file `validate_code`,
828
+ `ark_prepare_write`, and `createAICodeGate().validate()` are named lexical compatibility surfaces:
829
+ they may expose `lexicalValid`, but remain partial and `valid:false` until complete-candidate
830
+ preflight. Consumer-owned 1.0/1.1/1.2 `AdapterResult` values remain accepted by the public union.
756
831
 
757
832
  For hook-based enforcement, `ark-mcp --hook` runs one-shot: it reads a PreToolUse payload
758
833
  from stdin, validates the post-edit file content, and exits `2` with violations on stderr
@@ -795,8 +870,8 @@ registration by itself remains advisory on every host because the agent must cal
795
870
 
796
871
  1. **Read** manifest via `ark.manifest().toJSON()`
797
872
  2. **Generate** code using registered intents, profiles, metadata, projections, and workflow definitions
798
- 3. **Validate snippets** with `createAICodeGate().validate(source, { layer })`
799
- 4. **Validate repository** with `ark-check --root . --config ark.config.json`
873
+ 3. **Inspect snippets** with `createAICodeGate().validate(source, { layer })` (lexical, partial)
874
+ 4. **Validate the complete candidate** with `ark_prepare_change` or `ark-check --root . --config ark.config.json`
800
875
  5. **Lint** with `arkgate/eslint` recommended rules
801
876
  6. **Wire** relationships via `registry.define(..., { dependsOn, produces })`
802
877
  7. **Register** event contracts before publishing in strict mode
package/docs/ai-gates.md CHANGED
@@ -43,16 +43,21 @@ you pass `--force`, so review and commit only the templates that match your proj
43
43
  **Doctor (W5):** `ark-check --doctor --json` includes `doctor.writePath`
44
44
  (`mode`: `repair` | `reject-only` | `mcp-only` | `none`, plus `prepareWrite` /
45
45
  `autoPatch` flags), the supported profile for the active host, and the evidence actually found.
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
46
+ `writePath.enforcementState` separately reports `supported`, `analyzed`, `configured`, `installed`,
47
+ `runtimeObserved`, `operation`, `operationCoverage`, `active`, `bypassable`, `required`, and `hard`
48
+ with structured evidence for local hooks, advisory MCP, and CI. Its public schema is
49
+ `arkgate/schema/enforcement-state`; `enforcementLadder` remains a compatibility projection. Doctor
50
+ leaves hook trust and required-status policy `unverified` without runtime/provider evidence and
51
+ prints an explicit red flag for installed-but-unverified local hooks. Only a fresh covered
52
+ PreToolUse/provider observation can set operation-scoped `hard:true`. Codex
49
53
  `apply_patch` can expose a complete patch to the shared atomic preflight, but the host remains
50
54
  bypassable/advisory because some Code Mode paths do not dispatch the project hook.
51
55
 
52
56
  **Design fitness (3.0.1+):** the same doctor JSON may include `doctor.designFitness` and
53
57
  `doctor.designSmells[]` (path evidence). Edge-clean `operatingMode: enforce` can still set
54
- `designFitness.designWeak: true` (**ENFORCE · design-weak**). That is Shape residual, not a
55
- write-path failure. Companion plan JSON: `plan.patternBets[]` with `neverMechanicalSafe: true`
58
+ `designFitness.designWeak: true` (**ENFORCE · design-weak**). That global inventory remains Shape
59
+ residual, not a write-path failure. Separately, Z10's opt-in design delta blocks only new/worsened
60
+ supported smells on touched paths. Companion plan JSON: `plan.patternBets[]` with `neverMechanicalSafe: true`
56
61
  — never treat as write-boundary `autoPatch` / mechanical-safe. See
57
62
  [package-surface.md](package-surface.md) and [brownfield-adoption.md](brownfield-adoption.md) §6.
58
63
 
@@ -70,6 +75,14 @@ violations relative to the file's current on-disk state, so files with pre-exist
70
75
  (baselined) violations stay editable — they just can't get worse. New files block on
71
76
  every violation.
72
77
 
78
+ ### Opt-in resident hook pilot (Z07)
79
+
80
+ Set `ARK_RESIDENT_HOOK=1` on both `ark-mcp` and its hook command. The pilot reuses the
81
+ authoritative evaluator without caching decisions; stale inputs fall back one-shot.
82
+ It is off by default, and `ApplyPatch` always uses the atomic one-shot preflight.
83
+ With that MCP resident, `ark-check --doctor --json --resident` reuses canonical facts but
84
+ recomputes live doctor surfaces; an absent or invalid snapshot falls back to the cold CLI.
85
+
73
86
  ### Opt-in repair payload (W4)
74
87
 
75
88
  Default is **hard block with prose** on stderr. Hosts that can re-inject a fixed write
@@ -84,7 +97,12 @@ can enable a **machine-readable repair payload** (still exit `2` — **never** s
84
97
 
85
98
  ```json
86
99
  {
87
- "mode": "repair",
100
+ "schemaVersion": "1.3",
101
+ "mode": "lexical-compatibility",
102
+ "valid": false,
103
+ "completeness": "partial",
104
+ "completenessReasons": [{ "code": "LEXICAL_EVIDENCE_INCOMPLETE", "message": "…" }],
105
+ "repair": true,
88
106
  "decision": "deny",
89
107
  "filePath": "src/domain/use.ts",
90
108
  "layer": "DomainModel",
@@ -92,7 +110,9 @@ can enable a **machine-readable repair payload** (still exit `2` — **never** s
92
110
  "source": "import type { Row } from '../infra/types-only';\n…",
93
111
  "remediationKind": "import-type-from-pure-type-module",
94
112
  "confidence": 0.85,
95
- "valid": true
113
+ "valid": false,
114
+ "lexicalValid": true,
115
+ "completeness": "partial"
96
116
  }
97
117
  }
98
118
  ```
@@ -182,6 +202,10 @@ The MCP server exposes a resource and tools agents can use proactively (not an e
182
202
  - **`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.
183
203
  - **`ark_prepare_write`** (tool) — **W2:** place + constrain + validate + optional autoPatch + judgmentBrief + contentHash in one call (composes `ark_place` + write gate).
184
204
  - **`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.
205
+ - **3.7.0 corrective boundary:** the compiler-free candidate graph can miss aliases/workspace
206
+ edges that final TypeScript-backed CI resolves. Keep the strict CI backstop mandatory while
207
+ [Phase Z](https://github.com/pedroknigge/arkgate/blob/main/docs/plans/enforcement-truth-at-speed/README.md)
208
+ restores differential parity.
185
209
  - Blocking CLI/MCP/hook diagnostics include the same deterministic `nextAction`. `AGENTS.md`, skill
186
210
  catalogs, session prose, and live LLM calls are not inputs to the enforcement verdict.
187
211
  - **`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.
@@ -424,11 +448,11 @@ If your runtime can run a shell command before file writes and pass the tool pay
424
448
  - Grok payloads also get `{ "decision": "deny", "reason": "…" }` on stdout when blocked
425
449
  - plumbing problems (no stdin, non-source files, files outside `--root`) never block
426
450
 
427
- ## ESLint (editor feedback) — same contract as CI
451
+ ## ESLint (editor feedback) — bounded parity envelope
428
452
 
429
- For in-editor red squiggles that match **`arkgate-check`**, add the ESLint plugin.
453
+ For fast in-editor red squiggles, add the ESLint plugin.
430
454
  Layer imports and purity globals are driven by **`ark.config.json`** (walk-up from the
431
- linted file): same layer globs, specificity, `exclude`, and `rules[]` edges as the CI gate.
455
+ linted file).
432
456
 
433
457
  ```js
434
458
  // eslint.config.js (flat config)
@@ -438,28 +462,80 @@ export default [
438
462
  ark.configs.recommended,
439
463
  // no-domain-infra-imports → config-driven layer edges (type-only + value)
440
464
  // no-forbidden-globals → layer.forbiddenGlobals from ark.config.json
465
+ // ark/no-denied-capabilities → layer.capabilities.deny / layer.pure
441
466
  // no-raw-event-publish + require-publish-source → runtime event hygiene
442
467
  ];
443
468
  ```
444
469
 
445
- **Parity notes (2.5+):**
470
+ **Exact layer-edge parity envelope:** the linted production source is on disk, inside
471
+ `include`, outside configured/generated exclusions, parse-clean, and uses a static
472
+ `import`/`export` with a relative literal whose target is also on disk. Inside that envelope,
473
+ ESLint uses the same layer glob specificity, rule decision, rule id, severity, and evidence as
474
+ the resolved CLI. It reloads `ark.config.json` when its content changes and never invents a
475
+ not-yet-created target.
476
+
477
+ Outside that envelope—path aliases, packages/workspaces, symlinks, CommonJS,
478
+ `import = require`, dynamic imports, virtual creates/deletes, unresolved targets, or complete
479
+ cross-file candidates—ESLint emits no layer-parity verdict. Use `ark preflight`,
480
+ `ark_prepare_change`, the complete ApplyPatch hook, or final strict CI; those paths consume the
481
+ canonical resolved facts.
482
+
483
+ Additional rule notes:
446
484
 
447
- - Relative imports are resolved to on-disk TS/JS targets; package bare imports are left to CI/TS.
485
+ - Relative imports are resolved only to existing on-disk TS/JS targets; package bare imports are left to CI/TS.
448
486
  - Type-only and value forbidden edges both error (same pass/fail as `arkgate-check`).
449
- - `no-forbidden-globals` only applies when the file’s layer declares `forbiddenGlobals` (or you pass a `globals` option). Layers without a purity list are not inventively restricted.
450
- - Without `ark.config.json`, `no-domain-infra-imports` falls back to a domain→infra path heuristic.
487
+ - `no-forbidden-globals` applies from the file layer’s `forbiddenGlobals`; the `globals` option is only a standalone fallback when no project config applies, never an override that weakens the project contract. Layers without either surface are not inventively restricted. `process` also owns exact value imports of `process` / `node:process`; type-only forms, subpaths, and `child_process` stay excluded. If the same layer also denies the `process` capability, this rule is the single `FORBIDDEN_GLOBAL` voice.
488
+ - Without `ark.config.json`, `no-domain-infra-imports` emits no contract verdict.
451
489
 
452
490
  Rule ids are `ark/<kebab-name>`. Individual rules are also on `ark.rules` if you wire them by hand.
453
- Prefer keeping editor + CI on the same `ark.config.json` do not maintain a parallel globals list unless you intentionally override.
491
+ Prefer keeping editor + CI on the same `ark.config.json`. Use the rule-local `globals` list only
492
+ for standalone linting where no project contract applies.
454
493
 
455
494
  ## CI backstop
456
495
 
457
496
  Whatever the agent side does, run the merge profile in CI:
458
497
 
459
498
  ```yaml
460
- - run: npx ark-check --root . --config ark.config.json --strict-merge
499
+ - run: npx ark-check --root . --config ark.config.json --strict-merge --fail-on-new-smells --base-ref "${{ github.event.pull_request.base.sha || github.event.before }}"
500
+ ```
501
+
502
+ This explicit brownfield ratchet records schema `1.0` identities, touched paths, and stable
503
+ evidence; missing base exits `2`. Its first semantic smell is `domain-logic-in-ui`; residual,
504
+ path-only moves, and unrelated work stay green. Generated Claude/Grok hooks share the delta and
505
+ golden-pattern repair hint. MCP exposes the result but stays advisory.
506
+
507
+ Or use the repository's composite Action at a pinned release or commit:
508
+
509
+ ```yaml
510
+ - uses: pedroknigge/arkgate@v3.7.0
511
+ with:
512
+ root: .
513
+ config: ark.config.json
514
+ strict-config: 'true'
515
+ baseline: ''
516
+ version: ''
517
+ github-token: ${{ github.token }}
518
+ ```
519
+
520
+ | Action input | Default | Meaning |
521
+ |--------------|---------|---------|
522
+ | `root` | `.` | Project root to check. |
523
+ | `config` | `ark.config.json` | Config path relative to `root`. |
524
+ | `strict-config` | `true` | On the current Action revision, run the fail-closed `--strict` profile; an explicit older `version` uses its compatibility `--strict-config` path. |
525
+ | `baseline` | empty | Optional frozen-violation baseline; empty disables baseline mode. |
526
+ | `version` | empty | Optional exact npm version override; empty runs the code from the pinned Action revision. |
527
+ | `github-token` | empty | Token for a pull-request failure comment; empty skips the comment. |
528
+
529
+ For an additional local human-commit check, copy the shipped hook template:
530
+
531
+ ```bash
532
+ cp node_modules/arkgate/templates/hooks/pre-commit-ark .git/hooks/pre-commit
533
+ chmod +x .git/hooks/pre-commit
461
534
  ```
462
535
 
536
+ The template runs the project's architecture check before a commit. It is optional and local;
537
+ it does not replace the CI job or repository policy that makes the CI status required for merges.
538
+
463
539
  `--strict-merge` requires strict config plus the shared gate files (`AGENTS.md`, MCP config,
464
540
  and CI workflow) and fails on safety diagnostics. `--strict` is a compatibility alias. Neither
465
541
  profile requires an editor hook; add `--require-write-hook claude|grok` only when CI must verify
@@ -482,8 +558,8 @@ reported as lost static assurance; it does not imply that a runtime schema was b
482
558
 
483
559
  ### Scanner soundness envelope
484
560
 
485
- ArkGate uses the TypeScript compiler API for the governed source files. The repository scanner
486
- and `createAICodeGate({ typescript })` recognize these dependency forms:
561
+ ArkGate uses the TypeScript compiler API for the governed source files. The resolved candidate
562
+ scanner used by CLI/preflight/MCP/complete-patch hooks recognizes these dependency forms:
487
563
 
488
564
  - `import ... from 'literal'`, side-effect imports, and `export ... from 'literal'`;
489
565
  - TypeScript `import x = require('literal')` external-module references;
@@ -491,6 +567,12 @@ and `createAICodeGate({ typescript })` recognize these dependency forms:
491
567
  - relative, tsconfig path-alias, package, and installed workspace-package targets that resolve
492
568
  to source inside the project root. Third-party or escaped targets are deliberately not governed.
493
569
 
570
+ `createAICodeGate({ typescript })` recognizes the same syntax lexically, but it does not discover a
571
+ project resolver by itself. Its result is explicitly `mode: "lexical-compatibility"`,
572
+ `completeness: "partial"`, and `valid:false`; `lexicalValid` records whether those bounded checks
573
+ passed. A caller-supplied target resolver can improve feedback but does not turn the snippet into a
574
+ parity-capable complete-candidate verdict.
575
+
494
576
  Direct `import(expr)` emits `DYNAMIC_IMPORT_NOT_ALLOWLISTED`; direct `require(expr)` emits
495
577
  `DYNAMIC_REQUIRE_NOT_ALLOWLISTED`. They are warnings in the default reporting profile and fail
496
578
  `--strict-config` / `--strict-merge`. The existing `dynamicImportAllowlist` name is retained for
@@ -87,6 +87,12 @@ Layer fields:
87
87
  (`network`, `filesystem`, `clock`, `randomness`, `environment`, `process`, `persistence`);
88
88
  `pure: true` is the shorthand that denies all seven. Absence changes no verdict.
89
89
 
90
+ `forbiddenGlobals: ["process"]` covers the ambient binding plus exact runtime imports from
91
+ `process` and `node:process`. It does not imply the broader `process` capability wall: subpaths
92
+ and `child_process` remain outside this narrow dual, and statement-level `import type` /
93
+ `export type` declarations are excluded. Declare `capabilities.deny: ["process"]` when the whole
94
+ process module-capability family must be denied.
95
+
90
96
  Rule fields:
91
97
 
92
98
  - `from`, `to`, `allowed`, `message`, `peerIsolation`, `sliceFolders`
@@ -6,7 +6,7 @@ corrects the architecture instead of weakening the contract.
6
6
  ## Prerequisites
7
7
 
8
8
  - Ark installed in the repo (`ark-check`, agent gates optional for this demo)
9
- - [examples/hexagonal-order-api](../../examples/hexagonal-order-api/) cloned with dependencies
9
+ - [examples/hexagonal-order-api](https://github.com/pedroknigge/arkgate/tree/main/examples/hexagonal-order-api) cloned with dependencies
10
10
 
11
11
  ## Steps
12
12
 
@@ -70,5 +70,5 @@ Expected:
70
70
  - The error message points at the **layer edge**, not a generic lint rule.
71
71
  - The fix is a file move or port inversion — not editing `ark.config.json`.
72
72
 
73
- See also: [Break it on purpose](../../examples/hexagonal-order-api/README.md#break-it-on-purpose)
73
+ See also: [Break it on purpose](https://github.com/pedroknigge/arkgate/blob/main/examples/hexagonal-order-api/README.md#break-it-on-purpose)
74
74
  for two more exercises.
@@ -38,20 +38,20 @@ 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)
41
+ - [Co-pilot autopilot, end to end](https://github.com/pedroknigge/arkgate/blob/main/docs/demos/03-copilot-autopilot.md)
42
42
 
43
43
  ## Gallery starters
44
44
 
45
45
  | Archetype | Directory |
46
46
  |-----------|-----------|
47
- | `crud-product` | [examples/crud-product-starter](../../examples/crud-product-starter/) |
48
- | `api-backend` | [examples/api-backend-starter](../../examples/api-backend-starter/) |
49
- | `worker-pipeline` | [examples/worker-pipeline-starter](../../examples/worker-pipeline-starter/) |
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/) |
47
+ | `crud-product` | [examples/crud-product-starter](https://github.com/pedroknigge/arkgate/tree/main/examples/crud-product-starter) |
48
+ | `api-backend` | [examples/api-backend-starter](https://github.com/pedroknigge/arkgate/tree/main/examples/api-backend-starter) |
49
+ | `worker-pipeline` | [examples/worker-pipeline-starter](https://github.com/pedroknigge/arkgate/tree/main/examples/worker-pipeline-starter) |
50
+ | `multi-app-workspace` | [examples/multi-app-workspace-starter](https://github.com/pedroknigge/arkgate/tree/main/examples/multi-app-workspace-starter) |
51
+ | `vertical-slice-product` | [examples/vertical-slice-starter](https://github.com/pedroknigge/arkgate/tree/main/examples/vertical-slice-starter) |
52
+ | `ddd-bounded-contexts` | [examples/ddd-context-starter](https://github.com/pedroknigge/arkgate/tree/main/examples/ddd-context-starter) |
53
53
 
54
- Deep teaching example (runnable API + break exercises): [hexagonal-order-api](../../examples/hexagonal-order-api/).
54
+ Deep teaching example (runnable API + break exercises): [hexagonal-order-api](https://github.com/pedroknigge/arkgate/tree/main/examples/hexagonal-order-api).
55
55
 
56
56
  ## Brownfield vs greenfield
57
57
 
@@ -63,5 +63,5 @@ Deep teaching example (runnable API + break exercises): [hexagonal-order-api](..
63
63
  ## Related
64
64
 
65
65
  - [Agent integration guide](../agent-guide.md)
66
- - [Public demos](../demos/)
67
- - [Examples index](../../examples/README.md)
66
+ - [Public demos](https://github.com/pedroknigge/arkgate/tree/main/docs/demos)
67
+ - [Examples index](https://github.com/pedroknigge/arkgate/blob/main/examples/README.md)
@@ -10,7 +10,7 @@ npm install
10
10
  npm run check
11
11
  ```
12
12
 
13
- Pick by archetype — see [examples/README.md](../../examples/README.md).
13
+ Pick by archetype — see [examples/README.md](https://github.com/pedroknigge/arkgate/blob/main/examples/README.md).
14
14
 
15
15
  ## When to use a starter vs hexagonal-order-api
16
16
 
@@ -24,4 +24,4 @@ Pick by archetype — see [examples/README.md](../../examples/README.md).
24
24
  1. Run `ark-check --doctor`
25
25
  2. Install gates: `ark-check --install-agent-gates`
26
26
  3. Use `/ark-place` for new files
27
- 4. Optionally commit `ark-adoption-plan.json` from `--write-plan` alongside `ark.config.json`
27
+ 4. Optionally commit `ark-adoption-plan.json` from `--write-plan` alongside `ark.config.json`