arkgate 2.11.0 → 2.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,70 @@ All notable changes to ArkGate (`arkgate`; formerly `ark-runtime-kernel`) are do
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## 2.12.0 — 2026-07-10
8
+
9
+ ### Fixed
10
+
11
+ - **Install agent gates on temp roots:** skip rewriting the developer's real
12
+ `~/.codex/config.toml` when the project root is a temp/upgrade scratch and
13
+ `CODEX_HOME` is unset. Home MCP wire failures no longer fail an otherwise
14
+ successful repo gate install (sandbox/EPERM). Explicit `CODEX_HOME` and
15
+ `--codex-home` still wire as before.
16
+ - **Q1 coverage floors (broad include, 80/85/95):** Vitest thresholds statements/lines **≥80%**,
17
+ branches/functions **≥85%** on the **full product unit surface** (`src/**` + `bin/lib/**` +
18
+ `bin/ark-shared.mjs`; only process-entry shells excluded — no cherry-picked enforcement-core
19
+ include). Per-path critical floors: write-path-detect / auto-patch / prepare-write /
20
+ safety-diagnostics / baseline-key / graph-cycles at **≥95%** branch. Real branch-driving tests
21
+ under `tests/unit/static-check/` (critical + surface/topup/seam suites). Two consecutive
22
+ green `npm run test:coverage` captures (stmts/lines **92.71%**, branches **85%**, functions
23
+ **94.76%**; critical modules all **≥95%** branch).
24
+ - **agent-gates modularization:** thin facade (`bin/lib/agent-gates.mjs` ~100 LOC) re-exports
25
+ `gate-files`, `skill-install`, `ci-and-commands`, `mcp-adoption`, `install-migrate`,
26
+ `typescript-host`, `hook-templates`, `write-path-detect`, plus field/codex helpers.
27
+ `detectDeployPathQuality` extracted to `bin/lib/deploy-path.mjs` so `mcp-adoption.mjs` stays
28
+ under the 600 LOC module budget. Import hygiene on extract modules; `loadTypeScript` uses
29
+ `__arkCheckCli` for the nested arkgate TypeScript fallback.
30
+ - **Deny→repair CI proof:** `tests/unit/static-check/writePathDetect.test.ts` drives
31
+ shipped `bin/ark-mcp.mjs --hook --hook-repair` and asserts `ARK_REPAIR_JSON` /
32
+ `ARK_AUTOPATCH_JSON` on deny (exit 2); reject-only without repair flag still supported.
33
+ - **Dogfood write path repair:** local Claude/Grok hooks use `--hook-repair`; doctor
34
+ reports `writePath.mode = repair` on this tree.
35
+ - **Self-hosted AGENTS.md:** `--install-agent-gates --force` no longer overwrites library
36
+ mother-repo Identity (`skipped-self-hosted`).
37
+ - **hexagonal-order-api:** `safety.allowInMemory` for ephemeral demo kernel; prefer
38
+ `arkgate/runtime` imports; `npm run check` green under `--strict-config`.
39
+ - **multi-app / monorepo rules:** deny App→Persistence, Presentation→Domain, and
40
+ Persistence→Presentation (parity with crud-product starter).
41
+ - **Generated CI Node default lags local npm (again):** when a project had no
42
+ `.nvmrc` / `engines.node`, the Ark architecture gate workflow defaulted to
43
+ Node 22. Lockfiles written on Node 24/26 then failed `npm ci` with
44
+ "Missing: … from lock file" before `ark-check` ran — CI green, Ark red.
45
+ Detection order is now `.nvmrc` / `.node-version` → `engines.node` → **highest
46
+ `node-version` from sibling workflows** (excludes `ark-check.yml` so a stale
47
+ gate cannot re-pin itself) → default **24**. Refresh existing gates with
48
+ `ark-check --install-agent-gates --force` (or edit `node-version` in
49
+ `.github/workflows/ark-check.yml`).
50
+
51
+ ### Changed
52
+
53
+ - **Hook templates extracted** to `bin/lib/hook-templates.mjs` (agent-gates seam).
54
+ - **Write-path detect extracted** to `bin/lib/write-path-detect.mjs` (doctor W5; re-exported
55
+ from agent-gates).
56
+ - **Coverage thresholds** raised to Q1 floors on the broad include set: statements/lines **≥80**,
57
+ branches/functions **≥85**, critical write/safety modules **≥95%** branch (see Fixed above).
58
+ - **`/ark-explore` skill:** decision-grade recon — field path (run starters/checks),
59
+ installed hooks vs install templates, coupling via fan-in/exports (not LOC alone),
60
+ ranked “así te lo re-soluciono” rows only when residual changes action; ENFORCE /
61
+ empty plan treated as baseline, not the story. **v2.1:** output modes (recon vs
62
+ dual-plan seed, no multi-week roadmaps by default); path-correct vs design-correct
63
+ + semantic false-green; success signals and kill-switches on bets (anti-vanity).
64
+ - **`/ark-autopilot` skill:** explore-first (decision-grade), **dual plan** —
65
+ A remediation from `--plan` + B pattern/evolution bets (never auto-apply B as
66
+ mechanical-safe); empty plan no longer means “healthy” without explore/B.
67
+ - **Day-zero origin first:** `ark start` / `ark init` freeze `.ark/reports/origin.*`
68
+ immediately after `ark.config.json` exists and **before** agent docs, skills, and CI
69
+ templates. Later `--report` still shows evolution vs that snapshot.
70
+
7
71
  ## 2.11.0 — 2026-07-10
8
72
 
9
73
  Fail-closed enforcement hardening: `--strict` now combines contract coverage, installed-gate
package/README.md CHANGED
@@ -23,8 +23,8 @@ and makes sure a “green” check means something real.
23
23
  If you remember nothing else:
24
24
 
25
25
  ```text
26
- 1. npx arkgate start ← install shape + gates + origin report
27
- 2. /ark-autopilot ← in your agent: adopt, fix, leave gates on
26
+ 1. npx arkgate start ← walk tree contract **day-zero origin** → gates
27
+ 2. /ark-autopilot ← explore first, dual plan, safe fixes, leave gates on
28
28
  3. npx arkgate-check --doctor ← “where am I?” anytime (one status screen)
29
29
  ```
30
30
 
@@ -106,7 +106,7 @@ Full checklist (CI, MCP, Codex, imports): **[docs/migrate-from-ark-runtime-kerne
106
106
 
107
107
  ```bash
108
108
  npm install -D arkgate typescript
109
- npx arkgate start # setup + origin report
109
+ npx arkgate start # contract day-zero origin → gates + plan
110
110
  # in agent:
111
111
  # /ark-autopilot
112
112
  npx arkgate-check --doctor # status light + next action
@@ -117,11 +117,13 @@ Aliases `ark` / `ark-check` / `ark-mcp` still work. **npm / pnpm / yarn**. No in
117
117
  <details>
118
118
  <summary>What <code>/ark-autopilot</code> does under the hood (optional detail)</summary>
119
119
 
120
- 1. Setup if needed (`ark start`).
121
- 2. Origin architecture report (before picture in `.ark/reports/`).
122
- 3. Adoption: match contract to real folders, raise governed %.
123
- 4. Plan + safe auto-fixes; judgment when you ask for full apply.
124
- 5. Gates on + after report (evolution vs origin).
120
+ 1. Setup if needed (`ark start` — contract, then **day-zero origin**, then gates).
121
+ 2. **Explore pass** (decision-grade map of *this* product; field path when demos exist).
122
+ 3. **Dual plan:** **A** remediation from `--plan` (mechanical-safe only by default); **B** pattern/evolution bets (never auto-applied as mechanical-safe). Empty plan ≠ “healthy” without explore/B.
123
+ 4. Apply A re-check; judgment only when you ask for full apply.
124
+ 5. Gates on + latest report (evolution vs frozen origin).
125
+
126
+ Standalone recon without applying: `/ark-explore`.
125
127
 
126
128
  </details>
127
129
 
@@ -188,11 +190,14 @@ ark.config.json
188
190
  - **Presets:** hexagonal, layered, feature-sliced, monorepo, ui-surface, vertical-slice, ddd-bounded-contexts (+ aliases clean-architecture / onion-architecture). Layers start optional; doctor suggests tightening populated cores. Cross-slice / cross-context bans use optional `peerIsolation` rules.
189
191
  - **Frameworks:** Nest / Next / express / library layouts get sensible globs on init so day-one coverage is real.
190
192
  - **Brownfield:** baseline ratchet, refuse to freeze a wrong contract, `/ark-adopt` for mature trees.
191
- - **Agents:** skills install into Claude / Cursor / Codex / Grok; `ark start` freezes an origin report under `.ark/reports/`.
193
+ - **Agents:** skills install into Claude / Cursor / Codex / Grok; `ark start` freezes **day-zero origin** under `.ark/reports/` **before** agent docs/CI templates.
192
194
  - **Write protocol (2.10 / Track W):** mechanical-safe **autoPatch** on the write gate (`import type`); MCP **`ark_prepare_write`** (place + validate + patch + judgmentBrief); opt-in hook **`--hook-repair`** (`ARK_REPAIR_JSON`); doctor **`writePath`** (repair vs reject-only); loop-cost eval (`npm run eval:loop-cost`). Port-proof inject is **judgment** (arity change), not silent auto-apply.
193
195
  - **Fail-closed CI (2.11):** `--strict` combines config coverage, required CI/MCP/write gates,
194
196
  PreToolUse hook presence, and bypass diagnostics for dynamic imports, TypeScript suppressions,
195
197
  explicit `any` casts, InMemory runtime defaults, and disabled peer isolation.
198
+ - **Trust / coverage (2.12):** package unit-test floors on the broad product surface
199
+ (statements/lines **≥80%**, branches/functions **≥85%**; enforcement-critical modules **≥95%**
200
+ branch). Explore dual-plan + day-zero origin first (see above). Roadmap next: Q2 repair dogfood matrix.
196
201
  - **TypeScript:** project compilers 5.x / 6.x / 7.x — gate falls back to a nested JS-API TypeScript when TS 7’s main export is version-only ([docs/typescript-support.md](docs/typescript-support.md)).
197
202
 
198
203
  ### Why not only ESLint / dependency-cruiser / Nx?
@@ -214,7 +219,7 @@ ark.config.json
214
219
  ## Common commands
215
220
 
216
221
  ```bash
217
- npx arkgate start # guided setup + plan + origin report
222
+ npx arkgate start # guided setup: contract origin → gates → plan
218
223
  npx arkgate-check --doctor # health + Adoption gaps (not just fitness)
219
224
  npx arkgate-check --doctor --json # machine-readable doctor.adoption
220
225
  npx arkgate-check --strict # fail-closed CI + installed-gate/safety checks
package/bin/ark.mjs CHANGED
@@ -23,6 +23,32 @@ import { pinArkgateDevDependency, FALSE_GREEN_GAP_ID } from './lib/field-install
23
23
  const here = path.dirname(fileURLToPath(import.meta.url));
24
24
  const arkCheck = path.join(here, 'ark-check.mjs');
25
25
 
26
+ /**
27
+ * Day-zero architecture picture: freeze origin under `.ark/reports/` as soon as
28
+ * `ark.config.json` exists — **before** agent docs, skills, CI templates, or cleanups.
29
+ * Idempotent: origin is written only once (`--report` archive semantics).
30
+ */
31
+ function freezeDayZeroOrigin(root) {
32
+ const configPath = path.join(root, 'ark.config.json');
33
+ if (!fs.existsSync(configPath)) {
34
+ console.log(
35
+ ` Skip origin freeze — no ark.config.json yet. After init: ${arkCommand(root, 'ark-check', '--report ark-report.html')}`
36
+ );
37
+ return;
38
+ }
39
+ const originJson = path.join(root, '.ark', 'reports', 'origin.json');
40
+ const already = fs.existsSync(originJson);
41
+ console.log(
42
+ already
43
+ ? 'Architecture origin already frozen (.ark/reports/origin.*) — leaving it untouched.'
44
+ : 'Freezing day-zero architecture picture (origin) before agent docs / gates…'
45
+ );
46
+ runArkCheck(
47
+ ['--root', root, '--config', 'ark.config.json', '--report', 'ark-report.html'],
48
+ { cwd: root }
49
+ );
50
+ }
51
+
26
52
  function parseArgs(argv) {
27
53
  const args = {
28
54
  command: undefined,
@@ -330,6 +356,10 @@ async function init(args) {
330
356
  console.log('Skipped ark.config.json generation.');
331
357
  }
332
358
 
359
+ // Origin first: contract-on-tree picture before AGENTS.md / skills / CI templates.
360
+ console.log('');
361
+ freezeDayZeroOrigin(root);
362
+
333
363
  const installGates =
334
364
  nonInteractive || (await askYesNo(rl, 'Configure agent and CI gate templates?', true));
335
365
  if (installGates) {
@@ -357,7 +387,7 @@ async function init(args) {
357
387
  console.log(`Shape: ${archetype}. Plan: ${arkCommand(root, 'ark-check', '--recommend')}`);
358
388
  }
359
389
  console.log(
360
- `Freeze day-one architecture snapshot: ${arkCommand(root, 'ark-check', '--report ark-report.html')} (writes .ark/reports/origin.* once).`
390
+ `Day-zero origin: .ark/reports/origin.* (frozen once; later --report shows evolution vs origin).`
361
391
  );
362
392
  console.log(`Adoption health: ${arkCommand(root, 'ark-check', '--doctor')}`);
363
393
  return 0;
@@ -381,9 +411,11 @@ async function start(args) {
381
411
  try {
382
412
  console.log("Let's set up Ark for your project.");
383
413
  console.log(
384
- "I'll look at your code, suggest a shape, set up the guardrails, and show you a plan."
414
+ "I'll walk the tree, freeze a day-zero architecture picture, then set up guardrails and show a plan."
415
+ );
416
+ console.log(
417
+ 'Nothing in your product code is changed — only Ark config, then origin snapshot, then agent/CI templates.'
385
418
  );
386
- console.log('Nothing in your code is changed — this only adds Ark configuration.');
387
419
  if (nonInteractive && !args.yes) {
388
420
  console.log(
389
421
  'Non-interactive session (no TTY) — using guided defaults (same as --yes). Pass flags to override.'
@@ -440,10 +472,10 @@ async function start(args) {
440
472
  console.log(' Skipping arkgate package pin (--no-install).');
441
473
  }
442
474
 
443
- // 3) Set up config + gates. Greenfield → the shape's preset; an established repo → detection,
444
- // so the contract anchors to the directories you already have instead of aspirational globs.
475
+ // 3) Contract first (config only). Greenfield → shape preset; established repo → detection,
476
+ // so the contract anchors to directories you already have instead of aspirational globs.
445
477
  console.log('');
446
- console.log('Setting up Ark…');
478
+ console.log('Setting up Ark contract…');
447
479
  const configPath = path.join(root, 'ark.config.json');
448
480
  if (!fs.existsSync(configPath)) {
449
481
  const initArgs = ['--root', root, '--init'];
@@ -482,6 +514,15 @@ async function start(args) {
482
514
  } else {
483
515
  console.log(' Found an existing ark.config.json — keeping it.');
484
516
  }
517
+
518
+ // 4) Day-zero origin — freeze the architecture picture *before* agent docs / CI / skills.
519
+ // Later --report runs show evolution vs this snapshot. Idempotent (origin once).
520
+ console.log('');
521
+ freezeDayZeroOrigin(root);
522
+
523
+ // 5) Agent + CI gate templates (docs, hooks, skills) — after origin is frozen.
524
+ console.log('');
525
+ console.log('Installing agent and CI gate templates…');
485
526
  {
486
527
  const gateArgs = ['--root', root, '--install-agent-gates'];
487
528
  if (args.tools) gateArgs.push('--tools', args.tools);
@@ -489,7 +530,7 @@ async function start(args) {
489
530
  runArkCheck(gateArgs, { cwd: root });
490
531
  }
491
532
 
492
- // 4) Show the plan: what's safe to auto-fix vs what needs a decision.
533
+ // 6) Show the plan: what's safe to auto-fix vs what needs a decision.
493
534
  console.log('');
494
535
  console.log('Your architecture plan:');
495
536
  runArkCheck(['--root', root, '--config', 'ark.config.json', '--plan'], { cwd: root });
@@ -571,7 +612,7 @@ async function start(args) {
571
612
  planOk = false;
572
613
  }
573
614
 
574
- // 5) Plain-language wrap-up — one next step, status light only.
615
+ // 7) Plain-language wrap-up — one next step, status light only.
575
616
  // Modes are detected (Suggest/Adapt/Enforce), not user-picked settings.
576
617
  // Soft-block false-green using the same doctor adoption gap (no second detector).
577
618
  let falseGreenGap = null;
@@ -620,7 +661,7 @@ async function start(args) {
620
661
  console.log(' → reclassify I/O dirs out of Application; then /ark-autopilot for residual debt.');
621
662
  } else {
622
663
  console.log(' 1. In your agent: /ark-autopilot');
623
- console.log(' → origin report, adoption, plan, safe fixes, leave gates on.');
664
+ console.log(' → explore first, dual plan (remediation + pattern bets), safe fixes, leave gates on.');
624
665
  }
625
666
  console.log(` 2. Status anytime: ${arkCommand(root, 'ark-check', '--doctor')}`);
626
667
  console.log(` 3. After edits: ${arkCommand(root, 'ark-check', '--root . --config ark.config.json --strict-config')}`);
@@ -630,16 +671,8 @@ async function start(args) {
630
671
  );
631
672
  }
632
673
  console.log('');
633
- console.log('Optional later: --plan · --coverage · /ark-fix · /ark-place · ark upgrade');
634
-
635
- // 6) First architecture report — freezes an origin snapshot under .ark/reports/
636
- // so later --report runs can show evolution. Idempotent: origin is written only once.
637
- console.log('');
638
- console.log('Capturing architecture report (origin snapshot on first run)…');
639
- runArkCheck(
640
- ['--root', root, '--config', 'ark.config.json', '--report', 'ark-report.html'],
641
- { cwd: root }
642
- );
674
+ console.log('Day-zero origin is under .ark/reports/origin.* re-run --report later for evolution.');
675
+ console.log('Optional later: --plan · --coverage · /ark-explore · /ark-fix · /ark-place · ark upgrade');
643
676
  return 0;
644
677
  } finally {
645
678
  rl?.close();