arkgate 4.4.0 → 4.5.5
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 +71 -2
- package/README.md +7 -4
- package/bin/ark-check-runtime.mjs +38 -13
- package/bin/ark-layer-match.mjs +25 -12
- package/bin/lib/adapter-contract.mjs +5 -5
- package/bin/lib/analysis-engine.mjs +5 -5
- package/bin/lib/ci-and-commands.mjs +5 -0
- package/bin/lib/deep-module-coach.mjs +177 -0
- package/bin/lib/deepening-coach.mjs +177 -0
- package/bin/lib/doctor-plan.mjs +14 -0
- package/bin/lib/html-report-advisories.mjs +33 -0
- package/bin/lib/html-report-depth.mjs +9 -0
- package/bin/lib/html-report.mjs +8 -1
- package/bin/lib/improvement-compass-map.mjs +507 -0
- package/bin/lib/improvement-compass-types.mjs +85 -0
- package/bin/lib/improvement-compass.mjs +10 -561
- package/bin/lib/managed-upgrade-honesty.mjs +201 -0
- package/bin/lib/managed-upgrade.mjs +54 -4
- package/bin/lib/remediation.mjs +5 -5
- package/bin/lib/status-command.mjs +127 -2
- package/bin/lib/status-manifest.mjs +163 -14
- package/bin/lib/upgrade-whats-new.mjs +110 -0
- package/dist/eslint/index.cjs +2 -2
- package/dist/eslint/index.js +2 -2
- package/dist/index.cjs +28 -28
- package/dist/index.d.ts +126 -21
- package/dist/index.js +28 -28
- package/docs/README.md +5 -5
- package/docs/agent-guide.md +50 -8
- package/docs/brownfield-adoption.md +12 -0
- package/docs/develop.md +3 -1
- package/docs/package-surface.md +8 -6
- package/docs/product-voice.md +25 -1
- package/docs/use.md +33 -0
- package/package.json +1 -1
- package/schemas/ark.status-manifest.schema.json +28 -1
- package/server.json +2 -2
- package/templates/agent-skills/README.md +2 -2
- package/templates/agent-skills/ark-adopt/SKILL.md +13 -0
- package/templates/agent-skills/ark-explore/SKILL.md +21 -0
- package/templates/agent-skills/ark-fix/SKILL.md +7 -0
- package/templates/agent-skills/ark-loop/SKILL.md +7 -0
- package/templates/agent-skills/ark-place/SKILL.md +7 -0
- package/templates/agent-skills/ark-think/SKILL.md +7 -0
- package/templates/agent-skills/ark-upgrade/SKILL.md +14 -0
- package/templates/skills/ark-adopt.md +13 -0
- package/templates/skills/ark-explore.md +21 -0
- package/templates/skills/ark-fix.md +7 -0
- package/templates/skills/ark-loop.md +7 -0
- package/templates/skills/ark-place.md +7 -0
- package/templates/skills/ark-think.md +7 -0
- package/templates/skills/ark-upgrade.md +14 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,13 +5,82 @@ in the immutable pre-2.0 archive linked below.
|
|
|
5
5
|
|
|
6
6
|
## Unreleased
|
|
7
7
|
|
|
8
|
+
## 4.5.5 — 2026-08-11
|
|
9
|
+
|
|
10
|
+
**Patch** over **4.5.0**. Deep-module coach train plus upgrade **suggested improvements /
|
|
11
|
+
what’s new** so consumers know what to try after install. **No required config migration.**
|
|
12
|
+
No new skill names, sensors, or scores. Freezes held.
|
|
13
|
+
|
|
14
|
+
**Status: prepared** (implementation only; not yet on npm `latest` — remains `4.5.0` until
|
|
15
|
+
the publication checklist completes).
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
- **Deep-module coach (advisory):** `ark-check --doctor` JSON `doctor.deepModuleCoach` + human
|
|
20
|
+
section + HTML `data-advisory="deepModuleCoach"`. Hot paths from bounded git history
|
|
21
|
+
(`unavailable` + empty when history missing — never invent). Deepening candidates projected
|
|
22
|
+
only from existing design smells / physical cohesion / pilot / residual compass evidence —
|
|
23
|
+
empty when no evidence. Always `notAScore: true`; never flips gate verdicts. Pure helper
|
|
24
|
+
`buildDeepeningCandidates` (+ CLI gen mirror).
|
|
25
|
+
- **Product voice + skills:** lexicon for depth / seam / deletion test / test-at-public-interface
|
|
26
|
+
/ domain glossary / two-axis done. Existing skills (explore, think, place, fix, loop, adopt)
|
|
27
|
+
deepened; agent-skills 1:1. Compact router + agent-guide **two-axis done** (Enforce green ≠
|
|
28
|
+
feature done). Remediation port/inject `nextAction` prose includes test at the public interface.
|
|
29
|
+
- **Upgrade suggested improvements / what’s new:** `ark upgrade` JSON `whatsNew` + human block
|
|
30
|
+
lists concrete try/inspect actions (deep-module coach, improvement compass, session/status
|
|
31
|
+
honesty, two-axis done, self-service honesty). Always `notAScore`; never a gate input.
|
|
32
|
+
|
|
33
|
+
## 4.5.0 — 2026-08-10
|
|
34
|
+
|
|
35
|
+
**Minor** over 4.4.0. Session control-plane honesty (status/MCP improvement compass with explicit
|
|
36
|
+
modes), domain module fitness (split oversized pure modules), selective pure verification ratchet,
|
|
37
|
+
self-service upgrade activation honesty, and a short session recipe in product docs. **No required
|
|
38
|
+
config migration.** Codex remains advisory at write time. Skills and AGENTS projection never
|
|
39
|
+
enforce. **Status: published** (`arkgate@4.5.0` on npm `latest`; see `docs/releases/4.5.0.md`).
|
|
40
|
+
|
|
41
|
+
### Added
|
|
42
|
+
|
|
43
|
+
- **Status / MCP improvement compass honesty:** `ark status --json` and MCP `ark_status` always
|
|
44
|
+
project `improvementCompass` with explicit mode `full` \| `subset` \| `unavailable`, residual
|
|
45
|
+
lens ids, and `notAScore: true`. Incomplete or missing session facts never invent green residual.
|
|
46
|
+
When mode is `full`, residual ids are a subset of doctor residual for the same facts (report
|
|
47
|
+
snapshots store the thin slice). Residual never flips `valid` / strict-merge / `goal.met`.
|
|
48
|
+
Root helpers: `projectStatusImprovementCompass`, `STATUS_COMPASS_MODES`.
|
|
49
|
+
- **Session recipe (product docs):** identity bind → `ark status` → act on residual / `findingRef`;
|
|
50
|
+
run doctor when status compass mode is not `full`. Documented in use / agent-guide / develop —
|
|
51
|
+
no new skill names.
|
|
52
|
+
- **Managed upgrade self-service honesty:** `ark upgrade [--json]` surfaces `selfService` with
|
|
53
|
+
per-host write-path activation labels (`hard` \| `advisory` \| `unavailable`) and customized
|
|
54
|
+
content-identity preserve (`customizedPaths` / `customizedContentPreserved`). Soft hosts never
|
|
55
|
+
hard; upgrade never invents `hardWriteActive` from disk alone. Always `notAScore: true`. Human
|
|
56
|
+
output: “Self-service honesty” lines.
|
|
57
|
+
|
|
58
|
+
### Changed
|
|
59
|
+
|
|
60
|
+
- **Domain module fitness:** pure Domain `improvementCompass` monolith split into
|
|
61
|
+
`improvementCompassTypes` + `improvementCompassMap` + facade `improvementCompass` (public
|
|
62
|
+
re-exports unchanged). All three tracked in `check:module-budgets`; over-ceiling domain modules
|
|
63
|
+
require a behavior-preserving split — raising max alone is not done. CLI pure mirrors:
|
|
64
|
+
`improvement-compass-types.mjs`, `improvement-compass-map.mjs`, `improvement-compass.mjs`.
|
|
65
|
+
- **Critical pure verification ratchet:** selective verification islands on
|
|
66
|
+
`layerMatch` peerIsolation fail-closed (missing paths/slices),
|
|
67
|
+
`policyDeltaAcknowledgementMatches` (hash + finding-id set), and
|
|
68
|
+
`canPromoteInvariant` promote honesty. Property suites under `tests/property/` plus unit fixtures;
|
|
69
|
+
Stryker mutate ranges + critical groups `peer-isolation-fail-closed`,
|
|
70
|
+
`policy-delta-ack-match`, `invariant-promote-honesty`. Mutation remains cost-gated to full-matrix
|
|
71
|
+
CI / publish (`npm run test:mutation` via `test:confidence`) — **not** a whole-repo mutation claim.
|
|
72
|
+
Strict semantics unchanged.
|
|
73
|
+
|
|
74
|
+
**Freezes held:** no principle scores/ranks; no new skill names; no new ArkRules sensors; no LLM
|
|
75
|
+
verdict; projection never enforces; no false hard-write for soft hosts.
|
|
76
|
+
|
|
8
77
|
## 4.4.0 — 2026-08-09
|
|
9
78
|
|
|
10
79
|
**Minor** over 4.3.0. Improvement compass (architecture lenses as a `notAScore` projection of
|
|
11
80
|
existing sensors), doctor/HTML residual coaching, deeper skills + compact router for vibe-coder
|
|
12
81
|
and full-AI workflows, and product-only public docs. **No required config migration.** Codex remains
|
|
13
|
-
advisory at write time. Skills and AGENTS projection never enforce. **Status:
|
|
14
|
-
|
|
82
|
+
advisory at write time. Skills and AGENTS projection never enforce. **Status: published**
|
|
83
|
+
(`arkgate@4.4.0` on npm `latest`; see `docs/releases/4.4.0.md`).
|
|
15
84
|
|
|
16
85
|
### Added
|
|
17
86
|
|
package/README.md
CHANGED
|
@@ -16,8 +16,9 @@ and makes sure a “green” check means something real.
|
|
|
16
16
|
|
|
17
17
|
</div>
|
|
18
18
|
|
|
19
|
-
> **ArkGate 4.
|
|
20
|
-
>
|
|
19
|
+
> **ArkGate 4.5.5** is **prepared** (deep-module coach + upgrade what’s new). npm `latest` remains
|
|
20
|
+
> **4.5.0** until publish. [4.5.5 notes](docs/releases/4.5.5.md) · [4.5.0](docs/releases/4.5.0.md) ·
|
|
21
|
+
> [4.4.0](docs/releases/4.4.0.md) · [Docs hub](docs/README.md) · [Product voice](docs/product-voice.md)
|
|
21
22
|
|
|
22
23
|
---
|
|
23
24
|
|
|
@@ -208,8 +209,10 @@ for real systems. Details: [docs/production-hardening.md](docs/production-harden
|
|
|
208
209
|
| Config · package surface · TS | [configuration](docs/configuration.md) · [package-surface](docs/package-surface.md) · [typescript-support](docs/typescript-support.md) |
|
|
209
210
|
| Brownfield | [docs/brownfield-adoption.md](docs/brownfield-adoption.md) |
|
|
210
211
|
| Security | [SECURITY.md](SECURITY.md) |
|
|
211
|
-
|
|
|
212
|
-
|
|
|
212
|
+
| Prepared (4.5.5) | [docs/releases/4.5.5.md](docs/releases/4.5.5.md) · [CHANGELOG](CHANGELOG.md) |
|
|
213
|
+
| Current published (4.5.0 on npm `latest`) | [docs/releases/4.5.0.md](docs/releases/4.5.0.md) |
|
|
214
|
+
| Prior (4.4.0) | [docs/releases/4.4.0.md](docs/releases/4.4.0.md) |
|
|
215
|
+
| Prior (4.3.0) | [docs/releases/4.3.0.md](docs/releases/4.3.0.md) |
|
|
213
216
|
| Prior (4.2.1) | [docs/releases/4.2.1.md](docs/releases/4.2.1.md) |
|
|
214
217
|
| Previous (4.2.0) | [docs/releases/4.2.0.md](docs/releases/4.2.0.md) |
|
|
215
218
|
| Previous (4.1.1) | [docs/releases/4.1.1.md](docs/releases/4.1.1.md) |
|
|
@@ -1557,19 +1557,6 @@ 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
|
|
@@ -1599,6 +1586,40 @@ async function main() {
|
|
|
1599
1586
|
baselineStale: analysisComplete ? reportBaselineStale : null,
|
|
1600
1587
|
}
|
|
1601
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
|
+
});
|
|
1602
1623
|
const reportPayload = {
|
|
1603
1624
|
root,
|
|
1604
1625
|
config,
|
|
@@ -1623,6 +1644,10 @@ async function main() {
|
|
|
1623
1644
|
...(designDepth?.improvementCompass
|
|
1624
1645
|
? { improvementCompass: designDepth.improvementCompass }
|
|
1625
1646
|
: {}),
|
|
1647
|
+
// Doctor parity: deep-module coach advisory (hot paths + deepening; notAScore).
|
|
1648
|
+
...(designDepth?.deepModuleCoach
|
|
1649
|
+
? { deepModuleCoach: designDepth.deepModuleCoach }
|
|
1650
|
+
: {}),
|
|
1626
1651
|
},
|
|
1627
1652
|
};
|
|
1628
1653
|
const html = args.beginner
|
package/bin/ark-layer-match.mjs
CHANGED
|
@@ -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
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
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
|
|
@@ -82,18 +82,18 @@ function nextActionForDiagnostic(ruleId, evidence, violation) {
|
|
|
82
82
|
return 'Move the referenced type to a mutually allowed layer, use `import type`, then preflight again.';
|
|
83
83
|
}
|
|
84
84
|
if (violation.peerIsolation === true) {
|
|
85
|
-
return 'Extract the shared dependency to a shared layer, then preflight again.';
|
|
85
|
+
return 'Extract the shared dependency to a shared layer, test at the public interface, then preflight again.';
|
|
86
86
|
}
|
|
87
|
-
return `Define a port in ${evidence.fromLayer ?? 'the source layer'}, inject the ${evidence.toLayer ?? 'outer-layer'} implementation, then preflight again.`;
|
|
87
|
+
return `Define a port in ${evidence.fromLayer ?? 'the source layer'}, inject the ${evidence.toLayer ?? 'outer-layer'} implementation, test at the public interface, then preflight again.`;
|
|
88
88
|
}
|
|
89
89
|
if (ruleId === 'FORBIDDEN_GLOBAL') {
|
|
90
|
-
return `Inject ${evidence.target ?? 'the capability'} through a port, then preflight again.`;
|
|
90
|
+
return `Inject ${evidence.target ?? 'the capability'} through a port, test at the public interface, then preflight again.`;
|
|
91
91
|
}
|
|
92
92
|
if (ruleId === 'CAPABILITY_VIOLATION') {
|
|
93
|
-
return `Define a ${text(violation.capability) ?? 'capability'} port in ${evidence.fromLayer ?? 'the walled layer'}, bind the implementation outside it, then preflight again.`;
|
|
93
|
+
return `Define a ${text(violation.capability) ?? 'capability'} port in ${evidence.fromLayer ?? 'the walled layer'}, bind the implementation outside it, test at the public interface, then preflight again.`;
|
|
94
94
|
}
|
|
95
95
|
if (ruleId === 'CIRCULAR_DEPENDENCY') {
|
|
96
|
-
return 'Extract the shared dependency into a third module, then preflight again.';
|
|
96
|
+
return 'Extract the shared dependency into a third module, test at the public interface, then preflight again.';
|
|
97
97
|
}
|
|
98
98
|
if (ruleId === 'RAW_EVENT_PUBLISH')
|
|
99
99
|
return 'Publish through a registered intent creator, then run Ark again.';
|