arkgate 4.8.9 → 4.8.11
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 +111 -3
- package/README.md +5 -4
- package/bin/ark-check-runtime.mjs +8 -2
- package/bin/ark-check.mjs +3 -0
- package/bin/ark.mjs +18 -10
- package/bin/lib/adapter-contract-types.mjs +137 -0
- package/bin/lib/adapter-contract.mjs +4 -180
- package/bin/lib/adapter-finding-refs.mjs +63 -0
- package/bin/lib/agent-projection-formatters.mjs +151 -0
- package/bin/lib/agent-projection-merge.mjs +148 -0
- package/bin/lib/agent-projection-types.mjs +42 -0
- package/bin/lib/agent-projection.mjs +3 -309
- package/bin/lib/analysis-engine.mjs +6 -6
- package/bin/lib/architecture-scan.mjs +91 -4
- package/bin/lib/ark-order-facts.mjs +11 -4
- package/bin/lib/arkrule-file-hints.mjs +255 -20
- package/bin/lib/arkrules-sensors.mjs +364 -68
- package/bin/lib/baseline-key.mjs +45 -1
- package/bin/lib/config-contract.mjs +9 -3
- package/bin/lib/diagnostic-catalog.mjs +1 -0
- package/bin/lib/doctor-human.mjs +3 -3
- package/bin/lib/doctor-next-actions.mjs +3 -1
- package/bin/lib/field-install.mjs +23 -2
- package/bin/lib/first-run-help.mjs +69 -5
- package/bin/lib/project-root.mjs +70 -4
- package/bin/lib/resolved-candidate-facts.mjs +82 -1
- package/bin/lib/rules-inventory.mjs +7 -3
- package/bin/lib/upstream-report.mjs +330 -0
- package/bin/lib/violations.mjs +51 -15
- package/dist/{diagnosticCatalog-BrkOiwCk.d.ts → diagnosticCatalog-DiflIock.d.ts} +30 -41
- package/dist/eslint/index.cjs +4 -7
- package/dist/eslint/index.js +4 -7
- package/dist/index.cjs +28 -31
- package/dist/index.d.ts +52 -13
- package/dist/index.js +28 -31
- package/dist/nestjs/index.cjs +1 -1
- package/dist/nestjs/index.js +1 -1
- package/dist/runtime/index.cjs +11 -11
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.js +11 -11
- package/docs/README.md +3 -3
- package/docs/agent-guide.md +25 -1
- package/docs/ai-gates.md +8 -0
- package/docs/brownfield-adoption.md +30 -0
- package/docs/configuration.md +14 -1
- package/docs/diagnostics.md +10 -0
- package/docs/package-surface.md +5 -3
- package/docs/use.md +11 -0
- package/package.json +3 -2
- package/schemas/ark.config.schema.json +3 -2
- package/server.json +2 -2
- package/templates/agent-skills/ark-explore/SKILL.md +22 -1
- package/templates/skills/ark-explore.md +22 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,115 @@
|
|
|
3
3
|
All notable changes to ArkGate (`arkgate`; formerly `ark-runtime-kernel`) are documented here or
|
|
4
4
|
in the immutable pre-2.0 archive linked below.
|
|
5
5
|
|
|
6
|
+
## 4.8.11 — 2026-09-02
|
|
7
|
+
|
|
8
|
+
**Patch** over **4.8.10**. Nested `--config` with `--root` stays inside that
|
|
9
|
+
tree. Library Shape splits `adapterContract` and `agentProjection` so the AI
|
|
10
|
+
edits one concern at a time. **Write. Check. Ship.** **No required config migration.**
|
|
11
|
+
No `schemaVersion` bump. Does not close `K01` / `Z09`. No new skill names.
|
|
12
|
+
|
|
13
|
+
**Status: prepared** (tree candidate; npm `latest` remains **4.8.10** until the
|
|
14
|
+
signed-tag provenance workflow succeeds).
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
- Nested `--config` is a file path: `ark-check --root examples/app --config
|
|
18
|
+
examples/app/ark.config.json` no longer treats the nested config as a
|
|
19
|
+
walk-up filename and no longer scans the invoker `cwd` (`include` is relative
|
|
20
|
+
to `--root`). Basename walk-up still applies when `--config` is
|
|
21
|
+
`ark.config.json`.
|
|
22
|
+
- `doctorResidentWarm` CI budget ceiling is 680ms (~12% headroom after the
|
|
23
|
+
adapterContract split). Still far below one-shot doctor.
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
- Domain Shape: `adapterContract` types/schema and finding-ref helpers are
|
|
27
|
+
their own modules; the public facade stays under the god-module floors.
|
|
28
|
+
Callers still import `src/domain/adapterContract.ts`. CLI pure helpers follow
|
|
29
|
+
the DF03 split.
|
|
30
|
+
- Domain Shape: `agentProjection` types/markers, body/meta formatters, and
|
|
31
|
+
merge/stamp are their own modules; the public facade re-exports. Callers still
|
|
32
|
+
import `src/domain/agentProjection.ts`. Generated CLI children stay in
|
|
33
|
+
DomainModel so the facade does not import Tooling.
|
|
34
|
+
- Dev-tree pins: `browserslist` 4.28.8 (GHSA-73wf-gq98-2v4g) and `fast-uri`
|
|
35
|
+
3.1.7 (GHSA-5jgf-p345-68v8 and siblings). These are lock/override pins, not a
|
|
36
|
+
consumer API change.
|
|
37
|
+
|
|
38
|
+
## 4.8.10 — 2026-09-02
|
|
39
|
+
|
|
40
|
+
**Patch** over **4.8.9**. Amarilla first-aggregate sensors. Incomplete analysis
|
|
41
|
+
never looks green: an enforced sensor that cannot see its scope is not a pass.
|
|
42
|
+
**Write. Check. Ship.** **No required config migration.** No `schemaVersion` bump.
|
|
43
|
+
Does not close `K01` / `Z09`. No new skill names.
|
|
44
|
+
|
|
45
|
+
**Status: published** (on npm `latest`; see `docs/releases/4.8.10.md`).
|
|
46
|
+
|
|
47
|
+
### Added
|
|
48
|
+
- `arkgate report` / `ark report` on the existing dual bins: draft an upstream GitHub issue for
|
|
49
|
+
`pedroknigge/arkgate` (`package.json` `bugs.url`), never the consumer repo. Default prints the
|
|
50
|
+
draft (arkgate version + last-check snippet). Create only with `--submit` and
|
|
51
|
+
`--i-confirm-submit` (or TTY `Type submit to send`). `--yes` does not submit. Missing or
|
|
52
|
+
unauthenticated `gh` prints the draft and the exact `gh issue create` command, then exits 2.
|
|
53
|
+
Not `ark-check --report` (HTML). Does not close `K01` / `Z09`. No new skill names.
|
|
54
|
+
|
|
55
|
+
### Fixed
|
|
56
|
+
- Structural-hint budget: when eligible governed files exceed `coverage.maxFiles`
|
|
57
|
+
(default `400`), emit `ARKRULE_HINT_BUDGET_EXHAUSTED` with exact hinted/governed
|
|
58
|
+
counts and per-sensor reviewed N/M of scope. `--strict-config` fails if an
|
|
59
|
+
enforced hint sensor is truncated. No `arkrules.hintBudget` key.
|
|
60
|
+
- `--update-baseline` GitHub rewrite touches only `ark-check` / `arkgate-check`
|
|
61
|
+
invocation lines (`run:` / package scripts). It does not append `--baseline` to
|
|
62
|
+
`concurrency.group` or job-id lines that merely name the check. Writes outside
|
|
63
|
+
the three law files are announced (`Synced --baseline into: …`).
|
|
64
|
+
- DomainModel class sensors: method finder is paren-balanced, so a later broken
|
|
65
|
+
method is visible. Remaining truncation is reported (`shape analysed until
|
|
66
|
+
character N`), not silent green.
|
|
67
|
+
- One shared invariant-word list (`ensureInvariants` / `raise` / `record` / `.push(`).
|
|
68
|
+
Assignment `=` is distinct from `===` / `!==` / `<=` / `>=`. `pendingEvents = []`
|
|
69
|
+
is idiomatic; events-array `.push(` counts as publish. Object literals and
|
|
70
|
+
multiline params are not public fields.
|
|
71
|
+
- `ARKRULE_SCOPE_EMPTY` is not freezable, even with `--force`. It is a config
|
|
72
|
+
diagnostic, not code debt. No `allowEmptyScope` key.
|
|
73
|
+
- `ARKRULE_STRUCTURE` freeze keys include the sensor id (and symbol when present).
|
|
74
|
+
A freeze for `orchestration-only` does not silence `thin-adapter` or
|
|
75
|
+
`writes-via-aggregate` on the same file. v1 empty-target keys remain exact-match
|
|
76
|
+
only.
|
|
77
|
+
- Intent-prefix checks apply only at declared intent-reference sites (`publish` /
|
|
78
|
+
`subscribe` / `defineIntent` / `registerHandler`, `intent` / `onEvent` /
|
|
79
|
+
`reactsTo`, publish `metadata.source`). Not every string literal. No
|
|
80
|
+
`kernel.dtypePrefixes`. A kernel DType such as `Management.EvmInspection.Data`
|
|
81
|
+
does not trip `LAYER_INTENT_REFERENCE_VIOLATION`.
|
|
82
|
+
- A5: `writes-via-aggregate` treats `@/lib/db` (and local `…/db`) as an IO import
|
|
83
|
+
without opening tsconfig. Write tokens require callee `db` / `tx` / `client` /
|
|
84
|
+
`prisma` / `drizzle`; `repo.update(` is not a write. Optional resolved-import
|
|
85
|
+
facts: PersistenceAdapters layer is a driver.
|
|
86
|
+
- IO import hints match `postgres` and `drizzle-orm/postgres-js` (package
|
|
87
|
+
subpaths), in lockstep for ArkRules and ArkOrder. `require()` matches the same
|
|
88
|
+
packages.
|
|
89
|
+
- React/UI `.set()` is not `ARKORDER_GENERIC_UPDATE`. Only `plane` /
|
|
90
|
+
`orderPlane` callees (or a file that constructs `createOrderPlane`) count as ξ
|
|
91
|
+
mutation. `Map` / `URLSearchParams` / `useState` setters stay silent.
|
|
92
|
+
- `--sensors` success is not a validity verdict. Stdout names the contract-only
|
|
93
|
+
skip (`Contract + coverage-evidence only: no TypeScript, no analysis. Not a
|
|
94
|
+
validity verdict.`); `--json` stamps `notAVerdict` / `didNotRun` /
|
|
95
|
+
`partialMode=contract-only`. It does not print `Ark check passed`.
|
|
96
|
+
|
|
97
|
+
### Changed
|
|
98
|
+
- `coverage.maxFiles` schema description, configuration docs, and diagnostics name
|
|
99
|
+
that the same budget also bounds structural-hint preload for `orchestration-only`,
|
|
100
|
+
`thin-adapter`, and `writes-via-aggregate`.
|
|
101
|
+
- Brownfield: law-then-product PR sequence when a rule’s folder does not exist yet
|
|
102
|
+
(advisory or placeholder path, then product, then promote). STRUCTURE key compat
|
|
103
|
+
for v1 empty-target rows is documented.
|
|
104
|
+
- A10: baseline regenerate note lists
|
|
105
|
+
`ark-check --update-baseline --force --contract-session --author <steward>`.
|
|
106
|
+
Doctor concentration looks at `sensor` / `arkruleId`; orchestration-only
|
|
107
|
+
majority is code debt, not “Fixing the contract”. Short `--help`: `--sensors`
|
|
108
|
+
does not run analysis; `--help --all` lists `--update-baseline` / `--author`.
|
|
109
|
+
AO11 9-vs-7 is not a bug.
|
|
110
|
+
- A11: `--changed` bounds file-local structural sensors and hint load to the
|
|
111
|
+
touched files. Import-edge, layer, and cycle sensors still see the full
|
|
112
|
+
governed graph. Optional process-local hint cache by content hash. Does not
|
|
113
|
+
claim 170s becomes seconds. No second analysis engine.
|
|
114
|
+
|
|
6
115
|
## 4.8.9 — 2026-09-01
|
|
7
116
|
|
|
8
117
|
**Patch** over **4.8.8**. Field diagnostic honesty: doctor default homedir, live
|
|
@@ -15,8 +124,7 @@ intent-reference checks share the import classifier. Amarilla ArkOrder:
|
|
|
15
124
|
**No required config migration.** No `ark.config.json` schema bump. Does not close `K01` / `Z09`.
|
|
16
125
|
No new skill names.
|
|
17
126
|
|
|
18
|
-
**Status:
|
|
19
|
-
signed-tag provenance workflow succeeds).
|
|
127
|
+
**Status: published** (on npm `latest`; see `docs/releases/4.8.9.md`).
|
|
20
128
|
|
|
21
129
|
### Added
|
|
22
130
|
- Optional `arkOrder.appliesTo` globs (same engine as layers). `managedLayers`
|
|
@@ -72,7 +180,7 @@ payload-free inspector monitors. ArkOrder and first-contact docs gain honesty co
|
|
|
72
180
|
**No required config migration.** No `ark.config.json` schema bump. Does not close
|
|
73
181
|
`K01` / `Z09`.
|
|
74
182
|
|
|
75
|
-
**Status: published** (
|
|
183
|
+
**Status: published** (see `docs/releases/4.8.8.md`).
|
|
76
184
|
|
|
77
185
|
### Added
|
|
78
186
|
- Dual **`ark-dashboard` / `arkgate-dashboard`** bins render the loopback ArkRun
|
package/README.md
CHANGED
|
@@ -37,7 +37,7 @@ Works with Cursor, Claude, Codex, and Grok.
|
|
|
37
37
|
|
|
38
38
|
</div>
|
|
39
39
|
|
|
40
|
-
> **ArkGate 4.8.
|
|
40
|
+
> **ArkGate 4.8.11** is prepared on this tree; npm `latest` remains **4.8.10**.
|
|
41
41
|
> Write. Check. Ship. Adopted = required GitHub
|
|
42
42
|
> status running `arkgate-check --strict-merge`, or an explicit `advisory-only` stance.
|
|
43
43
|
> Status is compact (`arkgate-check --doctor`; `--all` for Details). Optional **ArkRun**
|
|
@@ -45,7 +45,7 @@ Works with Cursor, Claude, Codex, and Grok.
|
|
|
45
45
|
> (`arkgate/order`) stops the agent rewriting the few slow product decisions as CRUD;
|
|
46
46
|
> later pattern change is `proposeRelease` then `apply`.
|
|
47
47
|
> `@arkgate/runtime` is deprecated.
|
|
48
|
-
> [4.8.
|
|
48
|
+
> [4.8.11 prepared](docs/releases/4.8.11.md) · [4.8.10 published](docs/releases/4.8.10.md) · [4.8.9](docs/releases/4.8.9.md) · [4.8.8](docs/releases/4.8.8.md) · [4.8.7](docs/releases/4.8.7.md) · [4.8.6](docs/releases/4.8.6.md) · [4.8.5](docs/releases/4.8.5.md) · [4.8.4](docs/releases/4.8.4.md) · [4.8.3](docs/releases/4.8.3.md) · [4.8.2](docs/releases/4.8.2.md) · [4.8.1](docs/releases/4.8.1.md) · [4.8.0](docs/releases/4.8.0.md) · [Docs hub](docs/README.md) · [Voice](docs/product-voice.md)
|
|
49
49
|
|
|
50
50
|
---
|
|
51
51
|
|
|
@@ -342,8 +342,9 @@ Rename the three keys. Compact starters leave it off. Details:
|
|
|
342
342
|
| Config · package surface · TS | [configuration](docs/configuration.md) · [package-surface](docs/package-surface.md) · [typescript-support](docs/typescript-support.md) |
|
|
343
343
|
| Brownfield | [docs/brownfield-adoption.md](docs/brownfield-adoption.md) |
|
|
344
344
|
| Security | [SECURITY.md](SECURITY.md) |
|
|
345
|
-
| Prepared (4.8.
|
|
346
|
-
| Current published (4.8.
|
|
345
|
+
| Prepared (4.8.11; not published) | [docs/releases/4.8.11.md](docs/releases/4.8.11.md) · [CHANGELOG](CHANGELOG.md) |
|
|
346
|
+
| Current published (4.8.10 on npm `latest`) | [docs/releases/4.8.10.md](docs/releases/4.8.10.md) · [CHANGELOG](CHANGELOG.md) |
|
|
347
|
+
| Prior published (4.8.9) | [docs/releases/4.8.9.md](docs/releases/4.8.9.md) · [CHANGELOG](CHANGELOG.md) |
|
|
347
348
|
| Prior published (4.8.7) | [docs/releases/4.8.7.md](docs/releases/4.8.7.md) · [CHANGELOG](CHANGELOG.md) |
|
|
348
349
|
| Prior published (4.8.6) | [docs/releases/4.8.6.md](docs/releases/4.8.6.md) |
|
|
349
350
|
| Prior published (4.8.5) | [docs/releases/4.8.5.md](docs/releases/4.8.5.md) |
|
|
@@ -96,7 +96,7 @@ import {
|
|
|
96
96
|
writeArkRulesTemplates,
|
|
97
97
|
} from './lib/presets.mjs';
|
|
98
98
|
import { loadArkConfigContract, parseArkConfigJson } from './lib/config-contract.mjs';
|
|
99
|
-
import { checkUsage, checkUsageAll } from './lib/first-run-help.mjs';
|
|
99
|
+
import { checkUsage, checkUsageAll, withSensorsPartialModeHonesty } from './lib/first-run-help.mjs';
|
|
100
100
|
import { createAdapterResult } from './lib/adapter-contract.mjs';
|
|
101
101
|
import {
|
|
102
102
|
UNGOVERNED_PROBE_CAP,
|
|
@@ -1066,6 +1066,12 @@ function applyConfigRootWalkUp(args) {
|
|
|
1066
1066
|
args.configRoot = effective.configRoot;
|
|
1067
1067
|
args.configFound = effective.configFound;
|
|
1068
1068
|
args.writeRoot = effective.writeRoot;
|
|
1069
|
+
// Nested relative --config (`examples/app/ark.config.json`) must stay a resolved
|
|
1070
|
+
// file path under --root. Leaving the relative string makes readConfig join it
|
|
1071
|
+
// again and miss; walk-up used to latch the parent instead.
|
|
1072
|
+
if (effective.configFound && typeof effective.configPath === 'string') {
|
|
1073
|
+
args.config = effective.configPath;
|
|
1074
|
+
}
|
|
1069
1075
|
if (effective.walkedUp && effective.root !== path.resolve(args.root)) {
|
|
1070
1076
|
// Read paths (or write + --follow-config-root): adopt discovered config root.
|
|
1071
1077
|
args.root = effective.root;
|
|
@@ -1140,7 +1146,7 @@ async function main() {
|
|
|
1140
1146
|
|
|
1141
1147
|
if (args.sensors) {
|
|
1142
1148
|
const { runSensors } = await import('./lib/sensor-promote-cli.mjs');
|
|
1143
|
-
await runSensors(args, readConfig);
|
|
1149
|
+
await withSensorsPartialModeHonesty(args, () => runSensors(args, readConfig));
|
|
1144
1150
|
return;
|
|
1145
1151
|
}
|
|
1146
1152
|
|
package/bin/ark-check.mjs
CHANGED
|
@@ -41,6 +41,9 @@ function residentArgs(argv) {
|
|
|
41
41
|
// Same monorepo walk-up as full runtime (NEW-MONOREPO-CWD-WALKUP).
|
|
42
42
|
const effective = resolveEffectiveProjectRoot(args.root, { configName: args.config });
|
|
43
43
|
args.configRoot = effective.configRoot;
|
|
44
|
+
if (effective.configFound && typeof effective.configPath === 'string') {
|
|
45
|
+
args.config = effective.configPath;
|
|
46
|
+
}
|
|
44
47
|
if (effective.walkedUp) {
|
|
45
48
|
args.root = effective.root;
|
|
46
49
|
args.configWalkedUp = true;
|
package/bin/ark.mjs
CHANGED
|
@@ -36,6 +36,7 @@ import {
|
|
|
36
36
|
import { runStatusCommand } from './lib/status-command.mjs';
|
|
37
37
|
import { runAgentProjectionCommand } from './lib/agent-projection-command.mjs';
|
|
38
38
|
import { setupUsage, setupUsageAll, upgradeUsage } from './lib/first-run-help.mjs';
|
|
39
|
+
import { runUpstreamReportCommand } from './lib/upstream-report.mjs';
|
|
39
40
|
|
|
40
41
|
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
41
42
|
const arkCheck = path.join(here, 'ark-check.mjs');
|
|
@@ -45,20 +46,20 @@ Usage: arkgate dashboard [--url <snapshot-url>] [--interval <ms>]
|
|
|
45
46
|
Polls an ArkRun inspector; it does not start the kernel.`;
|
|
46
47
|
|
|
47
48
|
function withDashboardHelp(text, detailed) {
|
|
49
|
+
const extra = detailed
|
|
50
|
+
? ' arkgate dashboard [--url <snapshot-url>] [--interval <ms>]\n arkgate report [--root <project>] [--json] [--title <text>] [--finding <ref>] [--submit] [--i-confirm-submit]\n'
|
|
51
|
+
: '';
|
|
52
|
+
const extraDesc = detailed
|
|
53
|
+
? ' dashboard ANSI observability TUI (spawns ark-dashboard).\n report Draft an upstream GitHub issue for pedroknigge/arkgate. Create needs --submit plus confirm. --yes does not submit.\n'
|
|
54
|
+
: '';
|
|
48
55
|
if (detailed) {
|
|
49
56
|
return text
|
|
50
|
-
.replace(
|
|
51
|
-
|
|
52
|
-
' arkgate dashboard [--url <snapshot-url>] [--interval <ms>]\n arkgate agents-md [--root'
|
|
53
|
-
)
|
|
54
|
-
.replace(
|
|
55
|
-
' agents-md Version-matched',
|
|
56
|
-
' dashboard ANSI observability TUI against a running ArkRun inspector (spawns ark-dashboard).\n agents-md Version-matched'
|
|
57
|
-
);
|
|
57
|
+
.replace(' arkgate agents-md [--root', `${extra} arkgate agents-md [--root`)
|
|
58
|
+
.replace(' agents-md Version-matched', `${extraDesc} agents-md Version-matched`);
|
|
58
59
|
}
|
|
59
60
|
return text.replace(
|
|
60
61
|
' arkgate-check --doctor status — one next step\n',
|
|
61
|
-
' arkgate-check --doctor status — one next step\n arkgate dashboard observability TUI (inspector)\n'
|
|
62
|
+
' arkgate-check --doctor status — one next step\n arkgate dashboard observability TUI (inspector)\n arkgate report draft an upstream GitHub issue\n'
|
|
62
63
|
);
|
|
63
64
|
}
|
|
64
65
|
|
|
@@ -181,7 +182,7 @@ function parseArgs(argv) {
|
|
|
181
182
|
else if (!arg.startsWith('-') && args.command === undefined) {
|
|
182
183
|
args.command = arg;
|
|
183
184
|
// Dashboard owns its flags (--url/--interval); pass the rest through untouched.
|
|
184
|
-
if (arg === 'dashboard') {
|
|
185
|
+
if (arg === 'dashboard' || arg === 'report') {
|
|
185
186
|
args.passthrough = argv.slice(i + 1);
|
|
186
187
|
break;
|
|
187
188
|
}
|
|
@@ -946,6 +947,13 @@ async function main() {
|
|
|
946
947
|
});
|
|
947
948
|
}
|
|
948
949
|
|
|
950
|
+
if (args.command === 'report') {
|
|
951
|
+
return runUpstreamReportCommand({
|
|
952
|
+
root: args.root, json: args.json, yes: args.yes,
|
|
953
|
+
arkgateVersion: cliVersion(), argv: args.passthrough,
|
|
954
|
+
});
|
|
955
|
+
}
|
|
956
|
+
|
|
949
957
|
if (args.command === 'agents-md' || args.command === 'agent-projection') {
|
|
950
958
|
return runAgentProjectionCommand({
|
|
951
959
|
root: args.root,
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GENERATED FILE — do not edit by hand.
|
|
3
|
+
*
|
|
4
|
+
* Canonical algorithm: src/domain/adapterContractTypes.ts
|
|
5
|
+
* Regenerate: node scripts/generate-cli-pure.mjs
|
|
6
|
+
* Drift check: node scripts/generate-cli-pure.mjs --check
|
|
7
|
+
*
|
|
8
|
+
* Pure CLI helper (bin/lib/adapter-contract-types.mjs). Zero Node I/O.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* 1.5 adds stable finding refs on every factory-emitted diagnostic (ACS06):
|
|
13
|
+
* `findingRef`, `targetKey` (baseline-compatible), `docsCodePath`.
|
|
14
|
+
* 1.4 added optional evidence.arkruleId + evidence.arkruleSource (ADR 0012 / AR03).
|
|
15
|
+
*/
|
|
16
|
+
export const ARK_ANALYSIS_RESULT_SCHEMA_VERSION = '1.5';
|
|
17
|
+
/** Repo-relative diagnostics docs path (parity with ACS02 diagnostic catalog). */
|
|
18
|
+
export const ADAPTER_DIAGNOSTIC_DOCS_RELATIVE_PATH = 'docs/diagnostics.md';
|
|
19
|
+
export const ARK_ANALYSIS_RESULT_SCHEMA = {
|
|
20
|
+
$schema: 'https://json-schema.org/draft/2020-12/schema',
|
|
21
|
+
$id: 'https://unpkg.com/arkgate@3/schemas/ark.analysis-result.schema.json',
|
|
22
|
+
title: 'ArkGate analysis result',
|
|
23
|
+
type: 'object',
|
|
24
|
+
additionalProperties: false,
|
|
25
|
+
required: [
|
|
26
|
+
'schemaVersion',
|
|
27
|
+
'mode',
|
|
28
|
+
'valid',
|
|
29
|
+
'completeness',
|
|
30
|
+
'completenessReasons',
|
|
31
|
+
'diagnostics',
|
|
32
|
+
],
|
|
33
|
+
allOf: [
|
|
34
|
+
{
|
|
35
|
+
if: {
|
|
36
|
+
properties: { completeness: { enum: ['partial', 'unavailable'] } },
|
|
37
|
+
required: ['completeness'],
|
|
38
|
+
},
|
|
39
|
+
then: { properties: { valid: { const: false } } },
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
if: {
|
|
43
|
+
properties: {
|
|
44
|
+
mode: { const: 'resolved-candidate-facts' },
|
|
45
|
+
completeness: { enum: ['complete', 'partial'] },
|
|
46
|
+
},
|
|
47
|
+
required: ['mode', 'completeness'],
|
|
48
|
+
},
|
|
49
|
+
then: {
|
|
50
|
+
required: ['policyHash', 'resolverIdentity', 'factsHash', 'candidateTreeHash'],
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
if: {
|
|
55
|
+
properties: { completeness: { const: 'complete' } },
|
|
56
|
+
required: ['completeness'],
|
|
57
|
+
},
|
|
58
|
+
then: { properties: { completenessReasons: { maxItems: 0 } } },
|
|
59
|
+
else: { properties: { completenessReasons: { minItems: 1 } } },
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
properties: {
|
|
63
|
+
schemaVersion: { const: ARK_ANALYSIS_RESULT_SCHEMA_VERSION },
|
|
64
|
+
mode: { enum: ['lexical-compatibility', 'resolved-candidate-facts'] },
|
|
65
|
+
valid: { type: 'boolean' },
|
|
66
|
+
completeness: { enum: ['complete', 'partial', 'unavailable'] },
|
|
67
|
+
completenessReasons: {
|
|
68
|
+
type: 'array',
|
|
69
|
+
items: {
|
|
70
|
+
type: 'object',
|
|
71
|
+
additionalProperties: false,
|
|
72
|
+
required: ['code', 'message'],
|
|
73
|
+
properties: {
|
|
74
|
+
code: { type: 'string', minLength: 1 },
|
|
75
|
+
message: { type: 'string', minLength: 1 },
|
|
76
|
+
file: { type: 'string', minLength: 1 },
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
policyHash: { type: 'string', minLength: 1 },
|
|
81
|
+
resolverIdentity: { type: 'string', minLength: 1 },
|
|
82
|
+
factsHash: { type: 'string', minLength: 1 },
|
|
83
|
+
candidateTreeHash: { type: 'string', minLength: 1 },
|
|
84
|
+
diagnostics: {
|
|
85
|
+
type: 'array',
|
|
86
|
+
items: {
|
|
87
|
+
type: 'object',
|
|
88
|
+
additionalProperties: false,
|
|
89
|
+
required: ['ruleId', 'severity', 'message', 'location', 'evidence'],
|
|
90
|
+
properties: {
|
|
91
|
+
ruleId: { type: 'string', minLength: 1 },
|
|
92
|
+
severity: { enum: ['error', 'warning'] },
|
|
93
|
+
message: { type: 'string', minLength: 1 },
|
|
94
|
+
location: {
|
|
95
|
+
type: 'object',
|
|
96
|
+
additionalProperties: false,
|
|
97
|
+
required: ['file', 'line', 'column'],
|
|
98
|
+
properties: {
|
|
99
|
+
file: { type: 'string', minLength: 1 },
|
|
100
|
+
line: { type: 'integer', minimum: 1 },
|
|
101
|
+
column: { type: 'integer', minimum: 1 },
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
evidence: {
|
|
105
|
+
type: 'object',
|
|
106
|
+
additionalProperties: false,
|
|
107
|
+
properties: {
|
|
108
|
+
target: { type: 'string' },
|
|
109
|
+
fromLayer: { type: 'string' },
|
|
110
|
+
toLayer: { type: 'string' },
|
|
111
|
+
typeOnly: { type: 'boolean' },
|
|
112
|
+
targetTypeOnlyExports: { type: 'boolean' },
|
|
113
|
+
sourcePureTypeModule: { type: 'boolean' },
|
|
114
|
+
namedBindingsTypeOnly: { type: 'boolean' },
|
|
115
|
+
portProofEligible: { type: 'boolean' },
|
|
116
|
+
peerIsolation: { type: 'boolean' },
|
|
117
|
+
capability: { type: 'string', minLength: 1 },
|
|
118
|
+
edgeKind: { type: 'string', minLength: 1 },
|
|
119
|
+
arkruleId: { type: 'string', minLength: 1 },
|
|
120
|
+
arkruleSource: { type: 'string', minLength: 1 },
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
nextAction: { type: 'string', minLength: 1 },
|
|
124
|
+
/** ACS06 — compact multi-turn id; always derived from targetKey when emitted. */
|
|
125
|
+
findingRef: { type: 'string', minLength: 1, pattern: '^fnv1a-[0-9a-f]{8}$' },
|
|
126
|
+
/**
|
|
127
|
+
* ACS06 — baseline-compatible freeze identity
|
|
128
|
+
* (`ruleId|file|from|to|target` with optional `#N` occurrence suffix).
|
|
129
|
+
*/
|
|
130
|
+
targetKey: { type: 'string', minLength: 1 },
|
|
131
|
+
/** ACS06 — package-relative diagnostics anchor path. */
|
|
132
|
+
docsCodePath: { type: 'string', minLength: 1 },
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
};
|
|
@@ -9,73 +9,16 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import { deterministicNextAction } from './remediation.mjs';
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
* 1.4 added optional evidence.arkruleId + evidence.arkruleSource (ADR 0012 / AR03).
|
|
17
|
-
*/
|
|
18
|
-
export const ARK_ANALYSIS_RESULT_SCHEMA_VERSION = '1.5';
|
|
19
|
-
/** Repo-relative diagnostics docs path (parity with ACS02 diagnostic catalog). */
|
|
20
|
-
export const ADAPTER_DIAGNOSTIC_DOCS_RELATIVE_PATH = 'docs/diagnostics.md';
|
|
12
|
+
import { ARK_ANALYSIS_RESULT_SCHEMA_VERSION, } from './adapter-contract-types.mjs';
|
|
13
|
+
import { adapterDocsCodePath, adapterFindingOccurrenceTargetKeys, adapterFindingRefFromTargetKey, adapterFindingTargetKey, } from './adapter-finding-refs.mjs';
|
|
14
|
+
export { ADAPTER_DIAGNOSTIC_DOCS_RELATIVE_PATH, ARK_ANALYSIS_RESULT_SCHEMA, ARK_ANALYSIS_RESULT_SCHEMA_VERSION, } from './adapter-contract-types.mjs';
|
|
15
|
+
export { adapterDocsCodePath, adapterFindingOccurrenceTargetKeys, adapterFindingRefFromTargetKey, adapterFindingTargetKey, } from './adapter-finding-refs.mjs';
|
|
21
16
|
function text(value) {
|
|
22
17
|
return typeof value === 'string' && value.length > 0 ? value : undefined;
|
|
23
18
|
}
|
|
24
19
|
function positiveInteger(value, fallback) {
|
|
25
20
|
return Number.isInteger(value) && Number(value) > 0 ? Number(value) : fallback;
|
|
26
21
|
}
|
|
27
|
-
/**
|
|
28
|
-
* Baseline-compatible target key for a violation input.
|
|
29
|
-
* Field order and empty-string fallbacks **must** match `baselineKey` in
|
|
30
|
-
* `baselineKey.ts` — parity tests guard this so finding refs never orphan freezes.
|
|
31
|
-
*
|
|
32
|
-
* Note: uses raw ruleId/file strings (including empty) the same way baseline does;
|
|
33
|
-
* display `ruleId` / `location.file` may still normalize to ARK_UNKNOWN / `<unknown>`.
|
|
34
|
-
*/
|
|
35
|
-
export function adapterFindingTargetKey(violation) {
|
|
36
|
-
const ruleId = typeof violation.ruleId === 'string'
|
|
37
|
-
? violation.ruleId
|
|
38
|
-
: typeof violation.code === 'string'
|
|
39
|
-
? violation.code
|
|
40
|
-
: undefined;
|
|
41
|
-
const file = typeof violation.file === 'string' ? violation.file : undefined;
|
|
42
|
-
const fromLayer = typeof violation.fromLayer === 'string' ? violation.fromLayer : undefined;
|
|
43
|
-
const toLayer = typeof violation.toLayer === 'string' ? violation.toLayer : undefined;
|
|
44
|
-
const target = typeof violation.target === 'string' ? violation.target : undefined;
|
|
45
|
-
return [
|
|
46
|
-
ruleId,
|
|
47
|
-
file,
|
|
48
|
-
fromLayer ?? '',
|
|
49
|
-
toLayer ?? '',
|
|
50
|
-
target ?? '',
|
|
51
|
-
].join('|');
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Occurrence-aware target keys for a violation list (parity with baselineOccurrenceKeys).
|
|
55
|
-
* First occurrence keeps the historical base key; duplicates get `#N`.
|
|
56
|
-
*/
|
|
57
|
-
export function adapterFindingOccurrenceTargetKeys(violations) {
|
|
58
|
-
const counts = new Map();
|
|
59
|
-
return violations.map((violation) => {
|
|
60
|
-
const base = adapterFindingTargetKey(violation);
|
|
61
|
-
const occurrence = (counts.get(base) ?? 0) + 1;
|
|
62
|
-
counts.set(base, occurrence);
|
|
63
|
-
return occurrence === 1 ? base : `${base}#${occurrence}`;
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
/** FNV-1a finding ref from a baseline-compatible targetKey (not a security hash). */
|
|
67
|
-
export function adapterFindingRefFromTargetKey(targetKey) {
|
|
68
|
-
let hash = 0x811c9dc5;
|
|
69
|
-
for (let index = 0; index < targetKey.length; index += 1) {
|
|
70
|
-
hash ^= targetKey.charCodeAt(index);
|
|
71
|
-
hash = Math.imul(hash, 0x01000193);
|
|
72
|
-
}
|
|
73
|
-
return `fnv1a-${(hash >>> 0).toString(16).padStart(8, '0')}`;
|
|
74
|
-
}
|
|
75
|
-
/** Package-relative docs path with fragment for a public ruleId. */
|
|
76
|
-
export function adapterDocsCodePath(ruleId) {
|
|
77
|
-
return `${ADAPTER_DIAGNOSTIC_DOCS_RELATIVE_PATH}#${ruleId}`;
|
|
78
|
-
}
|
|
79
22
|
function nextActionForDiagnostic(ruleId, evidence, violation) {
|
|
80
23
|
return deterministicNextAction({
|
|
81
24
|
ruleId,
|
|
@@ -240,122 +183,3 @@ export function createAdapterResult(input) {
|
|
|
240
183
|
}
|
|
241
184
|
return { ...base, mode, valid: false, completeness, ...evidence };
|
|
242
185
|
}
|
|
243
|
-
export const ARK_ANALYSIS_RESULT_SCHEMA = {
|
|
244
|
-
$schema: 'https://json-schema.org/draft/2020-12/schema',
|
|
245
|
-
$id: 'https://unpkg.com/arkgate@3/schemas/ark.analysis-result.schema.json',
|
|
246
|
-
title: 'ArkGate analysis result',
|
|
247
|
-
type: 'object',
|
|
248
|
-
additionalProperties: false,
|
|
249
|
-
required: [
|
|
250
|
-
'schemaVersion',
|
|
251
|
-
'mode',
|
|
252
|
-
'valid',
|
|
253
|
-
'completeness',
|
|
254
|
-
'completenessReasons',
|
|
255
|
-
'diagnostics',
|
|
256
|
-
],
|
|
257
|
-
allOf: [
|
|
258
|
-
{
|
|
259
|
-
if: {
|
|
260
|
-
properties: { completeness: { enum: ['partial', 'unavailable'] } },
|
|
261
|
-
required: ['completeness'],
|
|
262
|
-
},
|
|
263
|
-
then: { properties: { valid: { const: false } } },
|
|
264
|
-
},
|
|
265
|
-
{
|
|
266
|
-
if: {
|
|
267
|
-
properties: {
|
|
268
|
-
mode: { const: 'resolved-candidate-facts' },
|
|
269
|
-
completeness: { enum: ['complete', 'partial'] },
|
|
270
|
-
},
|
|
271
|
-
required: ['mode', 'completeness'],
|
|
272
|
-
},
|
|
273
|
-
then: {
|
|
274
|
-
required: ['policyHash', 'resolverIdentity', 'factsHash', 'candidateTreeHash'],
|
|
275
|
-
},
|
|
276
|
-
},
|
|
277
|
-
{
|
|
278
|
-
if: {
|
|
279
|
-
properties: { completeness: { const: 'complete' } },
|
|
280
|
-
required: ['completeness'],
|
|
281
|
-
},
|
|
282
|
-
then: { properties: { completenessReasons: { maxItems: 0 } } },
|
|
283
|
-
else: { properties: { completenessReasons: { minItems: 1 } } },
|
|
284
|
-
},
|
|
285
|
-
],
|
|
286
|
-
properties: {
|
|
287
|
-
schemaVersion: { const: ARK_ANALYSIS_RESULT_SCHEMA_VERSION },
|
|
288
|
-
mode: { enum: ['lexical-compatibility', 'resolved-candidate-facts'] },
|
|
289
|
-
valid: { type: 'boolean' },
|
|
290
|
-
completeness: { enum: ['complete', 'partial', 'unavailable'] },
|
|
291
|
-
completenessReasons: {
|
|
292
|
-
type: 'array',
|
|
293
|
-
items: {
|
|
294
|
-
type: 'object',
|
|
295
|
-
additionalProperties: false,
|
|
296
|
-
required: ['code', 'message'],
|
|
297
|
-
properties: {
|
|
298
|
-
code: { type: 'string', minLength: 1 },
|
|
299
|
-
message: { type: 'string', minLength: 1 },
|
|
300
|
-
file: { type: 'string', minLength: 1 },
|
|
301
|
-
},
|
|
302
|
-
},
|
|
303
|
-
},
|
|
304
|
-
policyHash: { type: 'string', minLength: 1 },
|
|
305
|
-
resolverIdentity: { type: 'string', minLength: 1 },
|
|
306
|
-
factsHash: { type: 'string', minLength: 1 },
|
|
307
|
-
candidateTreeHash: { type: 'string', minLength: 1 },
|
|
308
|
-
diagnostics: {
|
|
309
|
-
type: 'array',
|
|
310
|
-
items: {
|
|
311
|
-
type: 'object',
|
|
312
|
-
additionalProperties: false,
|
|
313
|
-
required: ['ruleId', 'severity', 'message', 'location', 'evidence'],
|
|
314
|
-
properties: {
|
|
315
|
-
ruleId: { type: 'string', minLength: 1 },
|
|
316
|
-
severity: { enum: ['error', 'warning'] },
|
|
317
|
-
message: { type: 'string', minLength: 1 },
|
|
318
|
-
location: {
|
|
319
|
-
type: 'object',
|
|
320
|
-
additionalProperties: false,
|
|
321
|
-
required: ['file', 'line', 'column'],
|
|
322
|
-
properties: {
|
|
323
|
-
file: { type: 'string', minLength: 1 },
|
|
324
|
-
line: { type: 'integer', minimum: 1 },
|
|
325
|
-
column: { type: 'integer', minimum: 1 },
|
|
326
|
-
},
|
|
327
|
-
},
|
|
328
|
-
evidence: {
|
|
329
|
-
type: 'object',
|
|
330
|
-
additionalProperties: false,
|
|
331
|
-
properties: {
|
|
332
|
-
target: { type: 'string' },
|
|
333
|
-
fromLayer: { type: 'string' },
|
|
334
|
-
toLayer: { type: 'string' },
|
|
335
|
-
typeOnly: { type: 'boolean' },
|
|
336
|
-
targetTypeOnlyExports: { type: 'boolean' },
|
|
337
|
-
sourcePureTypeModule: { type: 'boolean' },
|
|
338
|
-
namedBindingsTypeOnly: { type: 'boolean' },
|
|
339
|
-
portProofEligible: { type: 'boolean' },
|
|
340
|
-
peerIsolation: { type: 'boolean' },
|
|
341
|
-
capability: { type: 'string', minLength: 1 },
|
|
342
|
-
edgeKind: { type: 'string', minLength: 1 },
|
|
343
|
-
arkruleId: { type: 'string', minLength: 1 },
|
|
344
|
-
arkruleSource: { type: 'string', minLength: 1 },
|
|
345
|
-
},
|
|
346
|
-
},
|
|
347
|
-
nextAction: { type: 'string', minLength: 1 },
|
|
348
|
-
/** ACS06 — compact multi-turn id; always derived from targetKey when emitted. */
|
|
349
|
-
findingRef: { type: 'string', minLength: 1, pattern: '^fnv1a-[0-9a-f]{8}$' },
|
|
350
|
-
/**
|
|
351
|
-
* ACS06 — baseline-compatible freeze identity
|
|
352
|
-
* (`ruleId|file|from|to|target` with optional `#N` occurrence suffix).
|
|
353
|
-
*/
|
|
354
|
-
targetKey: { type: 'string', minLength: 1 },
|
|
355
|
-
/** ACS06 — package-relative diagnostics anchor path. */
|
|
356
|
-
docsCodePath: { type: 'string', minLength: 1 },
|
|
357
|
-
},
|
|
358
|
-
},
|
|
359
|
-
},
|
|
360
|
-
},
|
|
361
|
-
};
|