arkgate 3.7.0 → 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 (77) hide show
  1. package/CHANGELOG.md +76 -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-mcp-runtime.mjs +1976 -0
  6. package/bin/ark-mcp.mjs +84 -1495
  7. package/bin/ark-shared.mjs +34 -38
  8. package/bin/ark.mjs +33 -66
  9. package/bin/lib/adapter-contract.mjs +161 -9
  10. package/bin/lib/agent-gates.mjs +1 -0
  11. package/bin/lib/analysis-completeness.mjs +28 -0
  12. package/bin/lib/analysis-engine.mjs +8 -8
  13. package/bin/lib/analysis-policy.mjs +27 -0
  14. package/bin/lib/architecture-scan.mjs +70 -357
  15. package/bin/lib/auto-patch.mjs +76 -8
  16. package/bin/lib/ci-and-commands.mjs +1 -1
  17. package/bin/lib/codex-home.mjs +43 -16
  18. package/bin/lib/design-delta.mjs +4 -0
  19. package/bin/lib/doctor-advisories.mjs +4 -3
  20. package/bin/lib/doctor-plan.mjs +40 -41
  21. package/bin/lib/enforcement-state.mjs +2 -0
  22. package/bin/lib/github-enforcement.mjs +443 -0
  23. package/bin/lib/hook-templates.mjs +12 -148
  24. package/bin/lib/html-report-advisories.mjs +1 -1
  25. package/bin/lib/html-report-depth.mjs +9 -0
  26. package/bin/lib/html-report.mjs +5 -5
  27. package/bin/lib/install-migrate.mjs +83 -79
  28. package/bin/lib/managed-upgrade.mjs +622 -0
  29. package/bin/lib/mcp-adoption.mjs +3 -1
  30. package/bin/lib/parse-health.mjs +6 -5
  31. package/bin/lib/port-proof.mjs +2 -2
  32. package/bin/lib/prepare-change.mjs +68 -38
  33. package/bin/lib/prepare-write.mjs +7 -1
  34. package/bin/lib/resident-doctor-client.mjs +55 -0
  35. package/bin/lib/resident-hook.mjs +247 -0
  36. package/bin/lib/resolved-candidate-facts.mjs +1160 -0
  37. package/bin/lib/scan-files.mjs +19 -6
  38. package/bin/lib/snippet-analysis.mjs +119 -0
  39. package/bin/lib/source-policy.mjs +24 -0
  40. package/bin/lib/typescript-host.mjs +15 -18
  41. package/bin/lib/unavailable-analysis.mjs +76 -0
  42. package/bin/lib/upgrade-command.mjs +115 -0
  43. package/bin/lib/weakest-link.mjs +21 -179
  44. package/bin/lib/write-path-capabilities.mjs +167 -16
  45. package/bin/lib/write-path-detect.mjs +3 -2
  46. package/dist/eslint/index.cjs +3 -3
  47. package/dist/eslint/index.d.ts +3 -0
  48. package/dist/eslint/index.js +3 -3
  49. package/dist/index.cjs +7 -7
  50. package/dist/index.d.ts +1073 -141
  51. package/dist/index.js +7 -7
  52. package/docs/agent-guide.md +103 -59
  53. package/docs/ai-gates.md +97 -16
  54. package/docs/demos/01-write-gate-self-correction.md +2 -2
  55. package/docs/enthusiast/README.md +10 -10
  56. package/docs/enthusiast/how-to-gallery-starter.md +2 -2
  57. package/docs/enthusiast/reference-commands.md +18 -1
  58. package/docs/enthusiast/tutorial-first-project.md +2 -2
  59. package/docs/package-surface.md +98 -12
  60. package/docs/typescript-support.md +109 -37
  61. package/package.json +32 -4
  62. package/schemas/ark.analysis-result.schema.json +159 -2
  63. package/schemas/ark.design-delta.schema.json +1 -0
  64. package/schemas/ark.enforcement-state.schema.json +84 -0
  65. package/schemas/ark.resolved-candidate-facts.schema.json +1 -0
  66. package/server.json +2 -2
  67. package/templates/skills/ark-explore.md +5 -5
  68. package/templates/skills/ark-fix.md +1 -1
  69. package/templates/skills/ark-runtime.md +15 -8
  70. package/templates/skills/ark-upgrade.md +122 -182
  71. package/bin/lib/ai-velocity.mjs +0 -293
  72. package/bin/lib/graph-cycles.mjs +0 -6
  73. package/bin/lib/safety-diagnostics.mjs +0 -284
  74. package/bin/lib/ts-resolve.mjs +0 -228
  75. package/dist/configTypes-DAPvBqK6.d.cts +0 -61
  76. package/dist/eslint/index.d.cts +0 -146
  77. 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:
@@ -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`.
@@ -202,7 +217,8 @@ persisted as a short Shape plan under the repo; not a gate requirement.
202
217
  **Full-skill agent co-pilot:** after explicitly installing the `/ark-*` pack, use
203
218
  `/ark-autopilot` (explore-first, dual plan A remediation + B pattern bets). Recon without
204
219
  applying: `/ark-explore`. The default compact router uses MCP/CLI directly. Never treat empty
205
- `--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`.
206
222
 
207
223
  `ark init --archetype <id>` maps playbook ids to named presets (`hexagonal`, `layered`,
208
224
  `feature-sliced`, `monorepo`). With `--yes` and no archetype, Ark auto-selects from
@@ -360,11 +376,18 @@ Prefer preparing the write before the host commits it to disk:
360
376
  | MCP **`ark_prepare_write`** | Place + constrain + validate + optional `autoPatch` + `judgmentBrief` + contentHash + optional `goldenPattern` in one call |
361
377
  | MCP **`ark_prepare_change`** | Validate one complete create/update/delete batch in memory; optional `changeMap` also returns structural convergence; never writes |
362
378
  | CLI **`ark preflight --changes <file> --json`** | Same atomic verdict and map convergence for hosts/scripts that do not call MCP |
363
- | 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. |
364
380
  | PreToolUse **`--hook-repair`** | On deny: `ARK_REPAIR_JSON` / `ARK_AUTOPATCH_JSON` on stderr (still exit 2 — never silent write) |
365
- | 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` |
366
383
  | Doctor **`goldenPattern`** | Optional Q03 advisory summary (`present` / `invalid`); never clears design-weak |
367
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
+
368
391
  Port-proof inject binding is **judgment** for auto-apply (signature/arity change), not write-path autoPatch.
369
392
  Full reference: [ai-gates.md](ai-gates.md). Loop-cost harness: `npm run eval:loop-cost`.
370
393
 
@@ -395,7 +418,18 @@ npx arkgate-check --install-agent-gates --tools claude,cursor,codex,grok
395
418
  | **Grok Build** | `.grok/hooks/ark-write-gate.json` + `.grok/config.toml` / `.mcp.json` | `.grok/skills/<name>/SKILL.md` |
396
419
 
397
420
  This is a path reference, not a guarantee table. Full copy-paste setups:
398
- [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.
399
433
 
400
434
  ## Experimental runtime: contract discovery
401
435
 
@@ -419,7 +453,11 @@ const contract = ark.manifest().toJSON();
419
453
  ```
420
454
 
421
455
  Use `@arkgate/runtime` only when evaluating the experimental kernel. The stable `arkgate` gate
422
- 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).
423
461
 
424
462
  Agents should read `contract` and `ark.observability.report()` before generating or modifying code.
425
463
 
@@ -503,7 +541,8 @@ contract, Ark records `interceptor.error` and keeps delivering the original even
503
541
 
504
542
  ## Code Generation Validation
505
543
 
506
- 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:
507
546
 
508
547
  ```ts
509
548
  import * as ts from 'typescript';
@@ -521,11 +560,13 @@ const result = gate.validate(generatedSource, {
521
560
  agentId: 'agent-1',
522
561
  layer: 'DomainModel',
523
562
  });
524
- if (!result.valid) {
563
+ if (!result.lexicalValid) {
525
564
  for (const v of result.violations) {
526
565
  console.log(v.code, v.message, v.suggestion);
527
566
  }
528
567
  }
568
+ // result.valid remains false: call ark_prepare_change / preflightResolvedChange,
569
+ // then run the final strict repository check.
529
570
  ```
530
571
 
531
572
  Passing the `typescript` module enables built-in AST/symbol checks for dependencies, forbidden
@@ -640,33 +681,17 @@ Example config:
640
681
  }
641
682
  ```
642
683
 
643
- `ark-check` resolves imports through the TypeScript module resolver against your
644
- `tsconfig.json` relative, path-alias (e.g. `@infra/db`), package/workspace imports,
645
- TypeScript `import = require()`, dynamic `import()`, and `require()` — plus string intent
646
- references. It also flags raw
647
- `publish()` calls, publish calls without `metadata.source`, and source intent literals
648
- whose resolved layer differs from the publishing file layer. Pass `--tsconfig <path>` to force one config
649
- for every file; otherwise each source file uses the nearest `tsconfig.json` above it (like
650
- `tsc`), so monorepos with per-package alias maps work under a single `--root`. It resolves
651
- modules the way your build does, but is intentionally not yet a full type-graph analyzer
652
- (cross-layer type-only references beyond the import specifier are out of scope).
653
-
654
- Repeat runs are cached in `node_modules/.cache/ark-check.json` — unchanged files skip the
655
- parse, while import edges always re-resolve against the live filesystem so the cache can
656
- never hide a new violation. Cache schema v9 also preserves each file's parse-diagnostic count
657
- and binds it to the TypeScript parser version, so a warm doctor run cannot silently turn
658
- unreadable governed syntax into a clean claim after a parser change.
659
- `--no-cache` disables it.
660
-
661
- `ark-check --doctor --json` reports that syntax honesty under `doctor.parseHealth`: exact
662
- scanned/affected/diagnostic totals plus a deterministic top-12 file list and honest overflow.
663
- It is advisory in this release — it does not change the verdict, design fitness, pattern bets,
664
- or violations — but an affected governed file must not be described as successfully inspected.
665
-
666
- `ark-check --json` also reports `warnings` for incomplete governance coverage: missing
667
- layers, unclassified included files, unmatched layer patterns, duplicate layers, and rules
668
- that reference unknown layers. These are advisory by default. Use `--strict-config` once a
669
- 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`.
670
695
 
671
696
  Use the optional ESLint plugin for fast local feedback aligned with CI:
672
697
 
@@ -678,9 +703,11 @@ export default [
678
703
  ];
679
704
  ```
680
705
 
681
- Rules: `ark/no-domain-infra-imports` (layer edges from `ark.config.json`, same semantics as
682
- `arkgate-check`), `ark/no-forbidden-globals` (per-layer `forbiddenGlobals`),
683
- `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).
684
711
 
685
712
  ## Runtime Observability
686
713
 
@@ -760,8 +787,8 @@ not replace your web framework, HTTP clients, or job scheduler.
760
787
  ## Write-Path Gate (MCP)
761
788
 
762
789
  The strongest place to constrain an AI agent is the moment it writes a file, not after.
763
- `arkgate-mcp` / `ark-mcp` exposes ArkGate over MCP (JSON-RPC over stdio; gate host needs a
764
- 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
765
792
  the write path:
766
793
 
767
794
  For a complete multi-file candidate, use `ark preflight --changes changes.json --json` or MCP
@@ -775,15 +802,32 @@ required, and `behavioralCompletion` remains `not-evaluated` even when structure
775
802
  npx ark-mcp --root . --config ark.config.json [--manifest ark.manifest.json]
776
803
  ```
777
804
 
778
- - **Resource `ark://manifest`** — contract discovery. Serve your exported
779
- `ark.manifest().toJSON()` via `--manifest`, or omit it to get the 11-layer profile
780
- (layers + rules) as the default contract.
781
- - **Tool `ark_recommend`** no args. Returns the deterministic application-shape plan
782
- (archetype, preset, phased adoption, analogy). Same as `ark-check --recommend --json`.
783
- - **Tool `validate_code`** args `{ source, layer?, filePath? }`. Runs `createAICodeGate`
784
- against the profile and (when a manifest is provided) the registered intent allowlist.
785
- Returns `{ valid, violations, layer }`; `isError` is `true` when invalid. If `layer` is
786
- 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.
787
831
 
788
832
  For hook-based enforcement, `ark-mcp --hook` runs one-shot: it reads a PreToolUse payload
789
833
  from stdin, validates the post-edit file content, and exits `2` with violations on stderr
@@ -826,8 +870,8 @@ registration by itself remains advisory on every host because the agent must cal
826
870
 
827
871
  1. **Read** manifest via `ark.manifest().toJSON()`
828
872
  2. **Generate** code using registered intents, profiles, metadata, projections, and workflow definitions
829
- 3. **Validate snippets** with `createAICodeGate().validate(source, { layer })`
830
- 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`
831
875
  5. **Lint** with `arkgate/eslint` recommended rules
832
876
  6. **Wire** relationships via `registry.define(..., { dependsOn, produces })`
833
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,16 +462,30 @@ 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
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.
450
- - Without `ark.config.json`, `no-domain-infra-imports` falls back to a domain→infra path heuristic.
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
491
  Prefer keeping editor + CI on the same `ark.config.json`. Use the rule-local `globals` list only
@@ -458,9 +496,46 @@ for standalone linting where no project contract applies.
458
496
  Whatever the agent side does, run the merge profile in CI:
459
497
 
460
498
  ```yaml
461
- - 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
462
534
  ```
463
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
+
464
539
  `--strict-merge` requires strict config plus the shared gate files (`AGENTS.md`, MCP config,
465
540
  and CI workflow) and fails on safety diagnostics. `--strict` is a compatibility alias. Neither
466
541
  profile requires an editor hook; add `--require-write-hook claude|grok` only when CI must verify
@@ -483,8 +558,8 @@ reported as lost static assurance; it does not imply that a runtime schema was b
483
558
 
484
559
  ### Scanner soundness envelope
485
560
 
486
- ArkGate uses the TypeScript compiler API for the governed source files. The repository scanner
487
- 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:
488
563
 
489
564
  - `import ... from 'literal'`, side-effect imports, and `export ... from 'literal'`;
490
565
  - TypeScript `import x = require('literal')` external-module references;
@@ -492,6 +567,12 @@ and `createAICodeGate({ typescript })` recognize these dependency forms:
492
567
  - relative, tsconfig path-alias, package, and installed workspace-package targets that resolve
493
568
  to source inside the project root. Third-party or escaped targets are deliberately not governed.
494
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
+
495
576
  Direct `import(expr)` emits `DYNAMIC_IMPORT_NOT_ALLOWLISTED`; direct `require(expr)` emits
496
577
  `DYNAMIC_REQUIRE_NOT_ALLOWLISTED`. They are warnings in the default reporting profile and fail
497
578
  `--strict-config` / `--strict-merge`. The existing `dynamicImportAllowlist` name is retained for
@@ -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`
@@ -1,7 +1,9 @@
1
1
  # Reference: commands and artifacts
2
2
 
3
3
  Product: **ArkGate** (`arkgate`). Prefer `arkgate` / `arkgate-check` / `arkgate-mcp`; aliases
4
- `ark` / `ark-check` / `ark-mcp` work for one major. TypeScript 5–7: [typescript-support.md](../typescript-support.md).
4
+ `ark` / `ark-check` / `ark-mcp` work for one major. The current source candidate supports packed
5
+ project TypeScript 5.9/6.0/7.0 with a physically distinct TypeScript 6 analysis host; published
6
+ 3.7.0 predates that correction: [typescript-support.md](../typescript-support.md).
5
7
 
6
8
  ## Recommendation
7
9
 
@@ -53,6 +55,21 @@ arkgate-check --watch
53
55
  In 3.1+, strict merge protects policy changes; preflight checks one complete batch without writing
54
56
  (`--change-map` adds structural convergence). MCP: `ark_policy_delta`, `ark_prepare_change`.
55
57
 
58
+ ## Analysis completeness
59
+
60
+ Current check envelopes use schema `1.3` and require `mode`, `completeness`, and
61
+ `completenessReasons`:
62
+
63
+ | Value | Meaning | Agent rule |
64
+ |-------|---------|------------|
65
+ | `complete` | All governed files were analyzed | A clean verdict may be trusted |
66
+ | `partial` | Governed parse diagnostics left evidence incomplete | Plan goal is false; strict merge fails |
67
+ | `unavailable` | No usable TypeScript analysis host | Plan goal is false; CLI exits `2` |
68
+
69
+ Doctor keeps the parse detail diagnostic, but never call a `partial` or `unavailable` result green.
70
+ Single-file lexical checks are always `partial`; use atomic preflight or the full check for a
71
+ resolved complete-candidate verdict.
72
+
56
73
  ## Plan classes (`--plan --json`)
57
74
 
58
75
  | `class` | Agent may auto-apply? | Examples (`remediationKind`) |
@@ -82,5 +82,5 @@ into `domain/`.
82
82
  ## Next steps
83
83
 
84
84
  - [How to pick your shape](how-to-pick-shape.md)
85
- - [Public demos](../demos/)
86
- - [Brownfield adoption](../brownfield-adoption.md) if you already have code
85
+ - [Public demos](https://github.com/pedroknigge/arkgate/tree/main/docs/demos)
86
+ - [Brownfield adoption](../brownfield-adoption.md) if you already have code