arkgate 4.3.0 → 4.5.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 (61) hide show
  1. package/CHANGELOG.md +81 -10
  2. package/README.md +11 -7
  3. package/bin/ark-check-runtime.mjs +50 -14
  4. package/bin/ark-layer-match.mjs +25 -12
  5. package/bin/lib/agent-projection.mjs +1 -1
  6. package/bin/lib/analysis-engine.mjs +5 -5
  7. package/bin/lib/ci-and-commands.mjs +11 -5
  8. package/bin/lib/doctor-plan.mjs +25 -0
  9. package/bin/lib/html-report-advisories.mjs +33 -0
  10. package/bin/lib/html-report-depth.mjs +24 -0
  11. package/bin/lib/html-report.mjs +8 -1
  12. package/bin/lib/improvement-compass-doctor.mjs +106 -0
  13. package/bin/lib/improvement-compass-map.mjs +507 -0
  14. package/bin/lib/improvement-compass-types.mjs +85 -0
  15. package/bin/lib/improvement-compass.mjs +79 -0
  16. package/bin/lib/managed-upgrade-honesty.mjs +201 -0
  17. package/bin/lib/managed-upgrade.mjs +37 -4
  18. package/bin/lib/status-command.mjs +127 -2
  19. package/bin/lib/status-manifest.mjs +187 -1
  20. package/dist/eslint/index.cjs +2 -2
  21. package/dist/eslint/index.js +2 -2
  22. package/dist/index.cjs +35 -35
  23. package/dist/index.d.ts +267 -5
  24. package/dist/index.js +35 -35
  25. package/docs/README.md +7 -6
  26. package/docs/agent-guide.md +50 -7
  27. package/docs/develop.md +9 -4
  28. package/docs/diagnostics.md +1 -1
  29. package/docs/package-surface.md +38 -34
  30. package/docs/product-voice.md +30 -1
  31. package/docs/use.md +67 -1
  32. package/package.json +1 -1
  33. package/schemas/ark.status-manifest.schema.json +53 -0
  34. package/server.json +2 -2
  35. package/templates/agent-skills/README.md +2 -2
  36. package/templates/agent-skills/ark-adopt/SKILL.md +20 -0
  37. package/templates/agent-skills/ark-architect/SKILL.md +21 -1
  38. package/templates/agent-skills/ark-autopilot/SKILL.md +25 -5
  39. package/templates/agent-skills/ark-contract/SKILL.md +20 -0
  40. package/templates/agent-skills/ark-coverage/SKILL.md +20 -0
  41. package/templates/agent-skills/ark-explain/SKILL.md +20 -0
  42. package/templates/agent-skills/ark-explore/SKILL.md +23 -3
  43. package/templates/agent-skills/ark-fix/SKILL.md +22 -2
  44. package/templates/agent-skills/ark-loop/SKILL.md +22 -2
  45. package/templates/agent-skills/ark-place/SKILL.md +20 -0
  46. package/templates/agent-skills/ark-runtime/SKILL.md +7 -0
  47. package/templates/agent-skills/ark-think/SKILL.md +20 -0
  48. package/templates/agent-skills/ark-upgrade/SKILL.md +20 -0
  49. package/templates/skills/ark-adopt.md +20 -0
  50. package/templates/skills/ark-architect.md +21 -1
  51. package/templates/skills/ark-autopilot.md +25 -5
  52. package/templates/skills/ark-contract.md +20 -0
  53. package/templates/skills/ark-coverage.md +20 -0
  54. package/templates/skills/ark-explain.md +20 -0
  55. package/templates/skills/ark-explore.md +23 -3
  56. package/templates/skills/ark-fix.md +22 -2
  57. package/templates/skills/ark-loop.md +22 -2
  58. package/templates/skills/ark-place.md +20 -0
  59. package/templates/skills/ark-runtime.md +7 -0
  60. package/templates/skills/ark-think.md +20 -0
  61. package/templates/skills/ark-upgrade.md +20 -0
package/CHANGELOG.md CHANGED
@@ -5,14 +5,86 @@ in the immutable pre-2.0 archive linked below.
5
5
 
6
6
  ## Unreleased
7
7
 
8
- ## 4.3.0 — 2026-08-09 (prepared)
8
+ ## 4.5.0 — 2026-08-10
9
9
 
10
- **Minor** over 4.2.1. Phase ACS agent contract surface: diagnostic code catalog, unified
11
- status snapshot, version-matched agent projection, Agent Skills packaging of the existing 13
12
- skills, stable finding refs, and maintainer placement A/B eval. **No required config migration.**
13
- Codex remains advisory at write time. Skills and AGENTS projection never enforce. Z09 / RB-11
14
- remain open. **Status: prepared** (`arkgate@4.3.0` not published yet; **4.2.1** remains on npm
15
- `latest` until publication).
10
+ **Minor** over 4.4.0. Session control-plane honesty (status/MCP improvement compass with explicit
11
+ modes), domain module fitness (split oversized pure modules), selective pure verification ratchet,
12
+ self-service upgrade activation honesty, and a short session recipe in product docs. **No required
13
+ config migration.** Codex remains advisory at write time. Skills and AGENTS projection never
14
+ enforce. **Status: prepared in tree — not published on npm until OIDC publish + `npm view` succeed**
15
+ (see `docs/releases/4.5.0.md`).
16
+
17
+ ### Added
18
+
19
+ - **Status / MCP improvement compass honesty:** `ark status --json` and MCP `ark_status` always
20
+ project `improvementCompass` with explicit mode `full` \| `subset` \| `unavailable`, residual
21
+ lens ids, and `notAScore: true`. Incomplete or missing session facts never invent green residual.
22
+ When mode is `full`, residual ids are a subset of doctor residual for the same facts (report
23
+ snapshots store the thin slice). Residual never flips `valid` / strict-merge / `goal.met`.
24
+ Root helpers: `projectStatusImprovementCompass`, `STATUS_COMPASS_MODES`.
25
+ - **Session recipe (product docs):** identity bind → `ark status` → act on residual / `findingRef`;
26
+ run doctor when status compass mode is not `full`. Documented in use / agent-guide / develop —
27
+ no new skill names.
28
+ - **Managed upgrade self-service honesty:** `ark upgrade [--json]` surfaces `selfService` with
29
+ per-host write-path activation labels (`hard` \| `advisory` \| `unavailable`) and customized
30
+ content-identity preserve (`customizedPaths` / `customizedContentPreserved`). Soft hosts never
31
+ hard; upgrade never invents `hardWriteActive` from disk alone. Always `notAScore: true`. Human
32
+ output: “Self-service honesty” lines.
33
+
34
+ ### Changed
35
+
36
+ - **Domain module fitness:** pure Domain `improvementCompass` monolith split into
37
+ `improvementCompassTypes` + `improvementCompassMap` + facade `improvementCompass` (public
38
+ re-exports unchanged). All three tracked in `check:module-budgets`; over-ceiling domain modules
39
+ require a behavior-preserving split — raising max alone is not done. CLI pure mirrors:
40
+ `improvement-compass-types.mjs`, `improvement-compass-map.mjs`, `improvement-compass.mjs`.
41
+ - **Critical pure verification ratchet:** selective verification islands on
42
+ `layerMatch` peerIsolation fail-closed (missing paths/slices),
43
+ `policyDeltaAcknowledgementMatches` (hash + finding-id set), and
44
+ `canPromoteInvariant` promote honesty. Property suites under `tests/property/` plus unit fixtures;
45
+ Stryker mutate ranges + critical groups `peer-isolation-fail-closed`,
46
+ `policy-delta-ack-match`, `invariant-promote-honesty`. Mutation remains cost-gated to full-matrix
47
+ CI / publish (`npm run test:mutation` via `test:confidence`) — **not** a whole-repo mutation claim.
48
+ Strict semantics unchanged.
49
+
50
+ **Freezes held:** no principle scores/ranks; no new skill names; no new ArkRules sensors; no LLM
51
+ verdict; projection never enforces; no false hard-write for soft hosts.
52
+
53
+ ## 4.4.0 — 2026-08-09
54
+
55
+ **Minor** over 4.3.0. Improvement compass (architecture lenses as a `notAScore` projection of
56
+ existing sensors), doctor/HTML residual coaching, deeper skills + compact router for vibe-coder
57
+ and full-AI workflows, and product-only public docs. **No required config migration.** Codex remains
58
+ advisory at write time. Skills and AGENTS projection never enforce. **Status: published**
59
+ (`arkgate@4.4.0` on npm `latest`; see `docs/releases/4.4.0.md`).
60
+
61
+ ### Added
62
+
63
+ - **Improvement compass:** doctor human section + `doctor.improvementCompass` JSON — closed set of
64
+ architecture **lenses** (SoC, DIP, domain alignment, …) with status `ok` / `residual` /
65
+ `not-instrumented` / `out-of-scope`, evidence refs, optional next action, capped `topResidual`,
66
+ always **`notAScore: true`**. Projected from existing smells, walls, cohesion, ArkRules, and
67
+ design-weak signals. Residual lenses never flip `valid`, strict-merge, or `goal.met`.
68
+ Out-of-scope locked for scalability, app security tooling, and full resilience. Type-only
69
+ placement debt (`failsStrict: false`) maps to **modularity** residual only (not coupling).
70
+ - **Optional status slice:** thin `improvementCompass.topResidual` on the status manifest schema for
71
+ Tooling pass-through — **`ark status` does not compute lenses yet**; agents should read doctor.
72
+ - **HTML report:** advisory section `data-advisory="improvementCompass"` (report parity with doctor).
73
+ - **Skills + compact router:** same **13** skill names deepened for vibe-coder outcomes — compass
74
+ preflight, anti false-done, AI-easy placement cues, out-of-scope honesty, Completion **Compass**
75
+ bullet. Compact start router surfaces residual lenses and forbids “done” on green edges alone.
76
+ - **Docs:** use / develop / agent-guide describe compass + Align/Stabilize/Shape in product language.
77
+
78
+ **Freezes held:** no principle scores/ranks; no new skill names; no new ArkRules sensors; no LLM
79
+ verdict; projection never enforces.
80
+
81
+ ## 4.3.0 — 2026-08-09
82
+
83
+ **Minor** over 4.2.1. Agent contract surface: diagnostic code catalog, unified status snapshot,
84
+ version-matched agent projection, Agent Skills packaging of the existing 13 skills, stable finding
85
+ refs, and maintainer placement A/B eval. **No required config migration.** Codex remains advisory
86
+ at write time. Skills and AGENTS projection never enforce. **Status: published**
87
+ (`arkgate@4.3.0` on npm `latest`).
16
88
 
17
89
  ### Added
18
90
 
@@ -58,15 +130,14 @@ remain open. **Status: prepared** (`arkgate@4.3.0` not published yet; **4.2.1**
58
130
  ### Docs / claims (ACS08)
59
131
 
60
132
  - Claims matrix refreshed for 4.3.0 agent-contract statements (**0 Contradicted** on public
61
- lanes). Release notes at `docs/releases/4.3.0.md` (**Status: prepared**). Public lanes name
62
- the prepared candidate while npm `latest` remains **4.2.1** until Trusted Publishing.
133
+ lanes). Release notes at `docs/releases/4.3.0.md` (**Status: published**). npm `latest` is **4.3.0**.
63
134
 
64
135
  ## 4.2.1 — 2026-08-08 (published)
65
136
 
66
137
  **Patch** over 4.2.0. Next.js **16.3** field compatibility: root `proxy.ts` (Next 16 network-boundary
67
138
  rename of middleware) is scanned and classified; eval fixtures and release-surface pins track
68
139
  `next@16.3.0`. **No required config migration.** Codex remains advisory at write time.
69
- **Status: published** (`arkgate@4.2.1` on npm `latest`).
140
+ **Status: published** (`arkgate@4.2.1`; superseded by 4.3.0 on `latest`).
70
141
 
71
142
  ### Fixed
72
143
 
package/README.md CHANGED
@@ -16,9 +16,8 @@ and makes sure a “green” check means something real.
16
16
 
17
17
  </div>
18
18
 
19
- > **ArkGate 4.3.0** is prepared (agent contract surface: catalog, status, projection, skills packaging, finding refs);
20
- > **4.2.1** remains on npm `latest` until publication.
21
- > [4.3.0 candidate](docs/releases/4.3.0.md) · [4.2.1](docs/releases/4.2.1.md) · [4.2.0](docs/releases/4.2.0.md) · [Docs hub](docs/README.md) · [Product voice](docs/product-voice.md)
19
+ > **ArkGate 4.4.0** is on npm `latest`. Tree is preparing **4.5.0** (session honesty + upgrade self-service) see [4.5.0 notes](docs/releases/4.5.0.md) (Status: prepared until publish).
20
+ > [4.5.0 notes](docs/releases/4.5.0.md) · [4.4.0](docs/releases/4.4.0.md) · [4.3.0](docs/releases/4.3.0.md) · [Docs hub](docs/README.md) · [Product voice](docs/product-voice.md)
22
21
 
23
22
  ---
24
23
 
@@ -44,10 +43,13 @@ npx arkgate-check --doctor # control plane: status light + primary next a
44
43
  ```
45
44
 
46
45
  That is the product. Doctor is the control plane — when stuck, do **primary next action #1**.
46
+ Doctor also shows an **improvement compass** (architecture lenses such as separation of concerns and
47
+ dependency inversion — **not a score**). Residual lenses mean Shape work may remain even when edges
48
+ are green. Details: [use.md — Improvement compass](docs/use.md#improvement-compass-not-a-score).
47
49
 
48
50
  ```text
49
- start → doctor → day-to-day (place + gate)
50
- ↘ optional /ark-autopilot after skill pack
51
+ start → doctor (+ compass) → day-to-day (place + gate)
52
+ ↘ optional /ark-autopilot after skill pack
51
53
  ```
52
54
 
53
55
  Aliases `ark` / `ark-check` / `ark-mcp` still work. npm / pnpm / yarn. No install lifecycle scripts.
@@ -206,8 +208,10 @@ for real systems. Details: [docs/production-hardening.md](docs/production-harden
206
208
  | Config · package surface · TS | [configuration](docs/configuration.md) · [package-surface](docs/package-surface.md) · [typescript-support](docs/typescript-support.md) |
207
209
  | Brownfield | [docs/brownfield-adoption.md](docs/brownfield-adoption.md) |
208
210
  | Security | [SECURITY.md](SECURITY.md) |
209
- | Prepared candidate (4.3.0) | [docs/releases/4.3.0.md](docs/releases/4.3.0.md) · [CHANGELOG](CHANGELOG.md) |
210
- | Current published (4.2.1) | [docs/releases/4.2.1.md](docs/releases/4.2.1.md) |
211
+ | Current release (4.4.0 on npm `latest`) | [docs/releases/4.4.0.md](docs/releases/4.4.0.md) · [CHANGELOG](CHANGELOG.md) |
212
+ | Next prepare (4.5.0) | [docs/releases/4.5.0.md](docs/releases/4.5.0.md) (prepared — not published until npm verify) |
213
+ | Prior (4.3.0) | [docs/releases/4.3.0.md](docs/releases/4.3.0.md) |
214
+ | Prior (4.2.1) | [docs/releases/4.2.1.md](docs/releases/4.2.1.md) |
211
215
  | Previous (4.2.0) | [docs/releases/4.2.0.md](docs/releases/4.2.0.md) |
212
216
  | Previous (4.1.1) | [docs/releases/4.1.1.md](docs/releases/4.1.1.md) |
213
217
  | Previous (4.1.0) | [docs/releases/4.1.0.md](docs/releases/4.1.0.md) |
@@ -1557,25 +1557,20 @@ async function main() {
1557
1557
  enforcement: enforcementForReport,
1558
1558
  config,
1559
1559
  });
1560
- const currentSnapshot = buildReportSnapshot({
1561
- root,
1562
- config,
1563
- coverage,
1564
- violations: activeViolations,
1565
- ok,
1566
- suppressed: suppressed.length,
1567
- version: arkPackageVersion(),
1568
- fileCountByLayer,
1569
- enforcement: enforcementForReport,
1570
- score: fitness.score,
1571
- mode: fitness.mode,
1572
- });
1573
1560
  // Origin is read before archive so the HTML can show "just created" vs deltas.
1574
1561
  const existingOrigin = args.resetOrigin
1575
1562
  ? null
1576
1563
  : readJsonSafe(path.join(reportsDir(root), 'origin.json'));
1577
1564
  // Pass the same baseline split as doctor so productHonesty dirty-freeze matches.
1578
1565
  const reportBaseline = readBaseline(root, args.baseline || '.ark-baseline.json');
1566
+ // Doctor parity for improvement compass: stale keys = baseline keys not in current occurrence set.
1567
+ // Only when analysis is complete — partial scans under-count current keys and inflate false stale residual
1568
+ // (same gate as doctor-plan: baselineStale: analysisComplete ? staleBaseline : null).
1569
+ const reportOccurrenceKeys = baselineOccurrenceKeys(violations);
1570
+ const reportCurrentKeys = new Set(reportOccurrenceKeys);
1571
+ const reportBaselineStale = reportBaseline.exists
1572
+ ? [...reportBaseline.keys].filter((key) => !reportCurrentKeys.has(key)).length
1573
+ : 0;
1579
1574
  const { adoption: adoptionForReport, designDepth } = buildReportDepthPayload(
1580
1575
  root,
1581
1576
  config,
@@ -1588,8 +1583,43 @@ async function main() {
1588
1583
  frozenKeys: reportBaseline.exists ? reportBaseline.keys.size : 0,
1589
1584
  activeCount: activeViolations.length,
1590
1585
  activeBlockingCount: blockingViolations.length,
1586
+ baselineStale: analysisComplete ? reportBaselineStale : null,
1591
1587
  }
1592
1588
  );
1589
+ // DF02 — thin status compass on report snapshot so `ark status` residual ⊆ doctor.
1590
+ const reportCompass =
1591
+ designDepth?.improvementCompass && designDepth.improvementCompass.notAScore === true
1592
+ ? {
1593
+ schemaVersion: '1.0',
1594
+ notAScore: true,
1595
+ mode: analysisComplete ? 'full' : 'subset',
1596
+ topResidual: Array.isArray(designDepth.improvementCompass.topResidual)
1597
+ ? designDepth.improvementCompass.topResidual
1598
+ : [],
1599
+ factsSource: 'report-snapshot',
1600
+ ...(analysisComplete
1601
+ ? {}
1602
+ : {
1603
+ reasonCode: 'FACTS_PARTIAL',
1604
+ reason:
1605
+ 'Report analysis was incomplete — status compass is a subset; re-run doctor/report for full residual.',
1606
+ }),
1607
+ }
1608
+ : null;
1609
+ const currentSnapshot = buildReportSnapshot({
1610
+ root,
1611
+ config,
1612
+ coverage,
1613
+ violations: activeViolations,
1614
+ ok,
1615
+ suppressed: suppressed.length,
1616
+ version: arkPackageVersion(),
1617
+ fileCountByLayer,
1618
+ enforcement: enforcementForReport,
1619
+ score: fitness.score,
1620
+ mode: fitness.mode,
1621
+ improvementCompass: reportCompass,
1622
+ });
1593
1623
  const reportPayload = {
1594
1624
  root,
1595
1625
  config,
@@ -1608,7 +1638,13 @@ async function main() {
1608
1638
  originJustCreated: !existingOrigin,
1609
1639
  adoption: adoptionForReport,
1610
1640
  designDepth,
1611
- advisories: computeDoctorAdvisories(root, config, coverage, rules, files, ts, parseHealth),
1641
+ advisories: {
1642
+ ...computeDoctorAdvisories(root, config, coverage, rules, files, ts, parseHealth),
1643
+ // Doctor parity: always emit improvement compass when doctor would (reportParity).
1644
+ ...(designDepth?.improvementCompass
1645
+ ? { improvementCompass: designDepth.improvementCompass }
1646
+ : {}),
1647
+ },
1612
1648
  };
1613
1649
  const html = args.beginner
1614
1650
  ? renderBeginnerHtmlReport(reportPayload)
@@ -258,6 +258,21 @@ function resolveSliceFolders(rule, layerName, layers) {
258
258
  const layer = (layers ?? []).find((l) => l.name === layerName);
259
259
  return inferSliceFoldersFromPatterns(layer?.patterns);
260
260
  }
261
+ /**
262
+ * PeerIsolation deny decision given resolved path/slice evidence (DF04 pure core).
263
+ *
264
+ * Fail-closed: missing path, no classifiable folders, or unclassifiable either
265
+ * side → deny. Same-slice → allow (return false). Cross-slice → deny.
266
+ */
267
+ export function peerIsolationMustDeny(input) {
268
+ if (!input.fromPath || !input.toPath)
269
+ return true;
270
+ if (input.folderCount <= 0)
271
+ return true;
272
+ if (!input.fromSlice || !input.toSlice)
273
+ return true;
274
+ return input.fromSlice !== input.toSlice;
275
+ }
261
276
  /**
262
277
  * Find the first denying rule for a layer edge.
263
278
  *
@@ -279,20 +294,18 @@ export function findDeniedEdgeRule(rules, from, to, options) {
279
294
  if (rule.peerIsolation) {
280
295
  const fromPath = options?.fromPath;
281
296
  const toPath = options?.toPath;
282
- // Isolation is active: without both paths we cannot prove same-slice.
283
- if (!fromPath || !toPath)
284
- return rule;
285
297
  const folders = resolveSliceFolders(rule, from, options?.layers);
286
- // Configured isolation without classifiable folders cannot allow.
287
- if (folders.length === 0)
288
- return rule;
289
- const fromSlice = sliceIdForPath(fromPath, folders);
290
- const toSlice = sliceIdForPath(toPath, folders);
291
- // Unclassifiable either side: cannot prove same-slice → deny.
292
- if (!fromSlice || !toSlice)
293
- return rule;
294
- if (fromSlice !== toSlice)
298
+ const fromSlice = fromPath && toPath ? sliceIdForPath(fromPath, folders) : undefined;
299
+ const toSlice = fromPath && toPath ? sliceIdForPath(toPath, folders) : undefined;
300
+ if (peerIsolationMustDeny({
301
+ fromPath,
302
+ toPath,
303
+ folderCount: folders.length,
304
+ fromSlice,
305
+ toSlice,
306
+ })) {
295
307
  return rule;
308
+ }
296
309
  continue; // same slice: this peerIsolation rule does not deny
297
310
  }
298
311
  // Classic deny — same-layer always allowed without peerIsolation
@@ -148,7 +148,7 @@ export function buildAgentProjectionBody(facts) {
148
148
  '',
149
149
  ];
150
150
  if (profile === 'compact') {
151
- lines.push('### Primary path', '', '1. Call `ark_identity` with `project.expectedRoot` at the exact project root; reuse root + `projectId` on Ark MCP calls.', '2. Read the contract with `ark_manifest` (same expectation). `ark://manifest` is compatibility-only / unverified.', '3. Place files inside configured layers; validate; run the check command above on violations — fix architecture, do not weaken the gate.', '', '### Contract layers (summary)', '', formatAgentProjectionLayers(layers), '');
151
+ lines.push('### Primary path', '', '1. Run doctor (`ark-check --doctor`) — status light + primary next action.', '2. Read the improvement compass (not a score). Name residual lenses in plain language; never “done” on green edges alone while residual remains.', '3. Call `ark_identity` with `project.expectedRoot` at the exact project root; reuse root + `projectId` on Ark MCP calls.', '4. Read the contract with `ark_manifest` (same expectation). `ark://manifest` is compatibility-only / unverified.', '5. Place files inside configured layers; validate; run the check command above on violations — fix architecture, do not weaken the gate.', '6. Single door: edges debt → fix; design-weak / residual shape lenses → map then guided apply with user OK.', '', '### Contract layers (summary)', '', formatAgentProjectionLayers(layers), '');
152
152
  }
153
153
  else {
154
154
  lines.push('### Contract layers', '', formatAgentProjectionLayers(layers), '', 'When creating a **new** kind of code that no layer covers, update `ark.config.json` first (`/ark-contract`), then place the file.', '', '### Diagnostic codes (short list)', '', formatAgentProjectionCatalogShortList(catalog, docsPath), '', '### Session truth', '', '- Machine snapshot: `ark status --json` (or MCP `ark_status`) — identity, activation honesty, last check, residual counts. **Not a score.**', '- Authoritative contract: `ark_manifest` after a matched `ark_identity` handshake.', '');