arkgate 4.8.10 → 4.8.13
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 +74 -2
- package/README.md +23 -32
- package/bin/ark-check-runtime.mjs +8 -0
- package/bin/ark-check.mjs +3 -0
- 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 +4 -4
- package/bin/lib/ark-order-doctor.mjs +154 -0
- package/bin/lib/ark-order-report.mjs +64 -0
- package/bin/lib/ark-order-sensors.mjs +1 -1
- package/bin/lib/diagnostic-catalog.mjs +2 -2
- package/bin/lib/doctor-advisories.mjs +91 -18
- package/bin/lib/doctor-human.mjs +2 -10
- package/bin/lib/doctor-plan.mjs +4 -3
- package/bin/lib/extra-merge-teeth.mjs +32 -4
- package/bin/lib/html-report-advisories.mjs +2 -0
- package/bin/lib/html-report-depth.mjs +8 -18
- package/bin/lib/html-report.mjs +16 -0
- package/bin/lib/project-root.mjs +70 -4
- package/bin/lib/remediation.mjs +5 -5
- package/bin/lib/rules-under-contract.mjs +14 -0
- package/bin/lib/start-preview.mjs +1 -0
- package/bin/lib/status-command.mjs +28 -0
- package/bin/lib/status-manifest.mjs +23 -0
- package/bin/lib/violations.mjs +10 -1
- package/dist/{diagnosticCatalog-biferT4R.d.ts → diagnosticCatalog-DA565Lja.d.ts} +22 -39
- package/dist/eslint/index.cjs +4 -4
- package/dist/eslint/index.js +4 -4
- package/dist/index.cjs +31 -31
- package/dist/index.d.ts +116 -12
- package/dist/index.js +31 -31
- package/dist/nestjs/index.cjs +1 -1
- package/dist/nestjs/index.js +1 -1
- package/dist/runtime/index.cjs +15 -15
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.js +15 -15
- package/docs/README.md +5 -4
- package/docs/agent-guide.md +2 -1
- package/docs/arkorder.md +28 -10
- package/docs/package-surface.md +3 -1
- package/docs/product-voice.md +9 -8
- package/docs/use.md +1 -1
- package/package.json +3 -2
- package/schemas/ark.status-manifest.schema.json +47 -0
- package/server.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,79 @@
|
|
|
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
|
+
## Unreleased
|
|
7
|
+
|
|
8
|
+
## 4.8.13 — 2026-09-06
|
|
9
|
+
|
|
10
|
+
**Patch** over **4.8.12**. Publish gate: remaining ArkOrder doctor/deny branches so
|
|
11
|
+
`test:confidence` / `release:npm` clears the 81% floor. Tag `v4.8.12` stands;
|
|
12
|
+
this is the ship. **Write. Check. Ship.** **No required config migration.** No
|
|
13
|
+
`schemaVersion` bump. Does not close `K01` / `Z09`. No new skill names. This
|
|
14
|
+
mother `ark.config.json` still does **not** turn `arkOrder` on.
|
|
15
|
+
|
|
16
|
+
**Status: prepared** (tree candidate; npm `latest` remains **4.8.11** until the
|
|
17
|
+
signed-tag provenance workflow succeeds).
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
- Confidence coverage: remaining ArkOrder doctor/deny `Next:` and HTML/doctor
|
|
21
|
+
residual paths so the publish job is not blocked by a 0.03-point branch miss.
|
|
22
|
+
|
|
23
|
+
## 4.8.12 — 2026-09-05
|
|
24
|
+
|
|
25
|
+
**Patch** over **4.8.11**. First-contact honesty for the optional ArkOrder extra.
|
|
26
|
+
Sensors, valve, and `arkgate/order` already shipped on 4.8.11; this projects
|
|
27
|
+
them through doctor / start / status / the check label, in plain words.
|
|
28
|
+
**Write. Check. Ship.** **No required config migration.** No `schemaVersion` bump.
|
|
29
|
+
Does not close `K01` / `Z09`. No new skill names. This mother `ark.config.json`
|
|
30
|
+
still does **not** turn `arkOrder` on.
|
|
31
|
+
|
|
32
|
+
**Status: prepared** (tree candidate; npm `latest` remains **4.8.11** until the
|
|
33
|
+
signed-tag provenance workflow succeeds).
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
- Doctor / HTML / status `arkOrder` section (`notAScore`), same envelope as
|
|
37
|
+
ArkRun. Absence is a silent row. When on: one-breath + named choices + leftover count.
|
|
38
|
+
- Check prints `[ArkOrder]` on `ARKORDER_*` denies (and `[ArkRun]` on
|
|
39
|
+
`ARKRUN_*`) so rewriting `plan` like a seat count reads as clearly as a bad import.
|
|
40
|
+
- `ark start` preview says extras stay off — layers only, they stop bad imports.
|
|
41
|
+
|
|
42
|
+
### Changed
|
|
43
|
+
- Merge-planes honesty now names enforced ArkOrder skip findings. The stamp
|
|
44
|
+
already claimed this plane; `failMergeWhen` now matches.
|
|
45
|
+
- First-contact copy (README, use, doctor, deny `Next:`, start, gallery) uses
|
|
46
|
+
the one-minute breath. No ξ / Haken / slaving on the first screen.
|
|
47
|
+
|
|
48
|
+
## 4.8.11 — 2026-09-02
|
|
49
|
+
|
|
50
|
+
**Patch** over **4.8.10**. Nested `--config` with `--root` stays inside that
|
|
51
|
+
tree. Library Shape splits `adapterContract` and `agentProjection` so the AI
|
|
52
|
+
edits one concern at a time. **Write. Check. Ship.** **No required config migration.**
|
|
53
|
+
No `schemaVersion` bump. Does not close `K01` / `Z09`. No new skill names.
|
|
54
|
+
|
|
55
|
+
**Status: published** (on npm `latest`; see `docs/releases/4.8.11.md`).
|
|
56
|
+
|
|
57
|
+
### Fixed
|
|
58
|
+
- Nested `--config` is a file path: `ark-check --root examples/app --config
|
|
59
|
+
examples/app/ark.config.json` no longer treats the nested config as a
|
|
60
|
+
walk-up filename and no longer scans the invoker `cwd` (`include` is relative
|
|
61
|
+
to `--root`). Basename walk-up still applies when `--config` is
|
|
62
|
+
`ark.config.json`.
|
|
63
|
+
- `doctorResidentWarm` CI budget ceiling is 680ms (~12% headroom after the
|
|
64
|
+
adapterContract split). Still far below one-shot doctor.
|
|
65
|
+
|
|
66
|
+
### Changed
|
|
67
|
+
- Domain Shape: `adapterContract` types/schema and finding-ref helpers are
|
|
68
|
+
their own modules; the public facade stays under the god-module floors.
|
|
69
|
+
Callers still import `src/domain/adapterContract.ts`. CLI pure helpers follow
|
|
70
|
+
the DF03 split.
|
|
71
|
+
- Domain Shape: `agentProjection` types/markers, body/meta formatters, and
|
|
72
|
+
merge/stamp are their own modules; the public facade re-exports. Callers still
|
|
73
|
+
import `src/domain/agentProjection.ts`. Generated CLI children stay in
|
|
74
|
+
DomainModel so the facade does not import Tooling.
|
|
75
|
+
- Dev-tree pins: `browserslist` 4.28.8 (GHSA-73wf-gq98-2v4g) and `fast-uri`
|
|
76
|
+
3.1.7 (GHSA-5jgf-p345-68v8 and siblings). These are lock/override pins, not a
|
|
77
|
+
consumer API change.
|
|
78
|
+
|
|
6
79
|
## 4.8.10 — 2026-09-02
|
|
7
80
|
|
|
8
81
|
**Patch** over **4.8.9**. Amarilla first-aggregate sensors. Incomplete analysis
|
|
@@ -10,8 +83,7 @@ never looks green: an enforced sensor that cannot see its scope is not a pass.
|
|
|
10
83
|
**Write. Check. Ship.** **No required config migration.** No `schemaVersion` bump.
|
|
11
84
|
Does not close `K01` / `Z09`. No new skill names.
|
|
12
85
|
|
|
13
|
-
**Status:
|
|
14
|
-
signed-tag provenance workflow succeeds).
|
|
86
|
+
**Status: published** (on npm `latest`; see `docs/releases/4.8.10.md`).
|
|
15
87
|
|
|
16
88
|
### Added
|
|
17
89
|
- `arkgate report` / `ark report` on the existing dual bins: draft an upstream GitHub issue for
|
package/README.md
CHANGED
|
@@ -37,15 +37,15 @@ Works with Cursor, Claude, Codex, and Grok.
|
|
|
37
37
|
|
|
38
38
|
</div>
|
|
39
39
|
|
|
40
|
-
> **ArkGate 4.8.
|
|
40
|
+
> **ArkGate 4.8.13** is prepared on this tree; npm `latest` remains **4.8.11**.
|
|
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**
|
|
44
44
|
> (`arkgate/runtime`) is an in-memory runtime — not Postgres. Optional **ArkOrder**
|
|
45
|
-
> (`arkgate/order`) stops
|
|
46
|
-
>
|
|
45
|
+
> (`arkgate/order`) stops rewriting a big product choice — like the billing plan —
|
|
46
|
+
> as if it were a seat count. Change those choices through a valve, not a generic update.
|
|
47
47
|
> `@arkgate/runtime` is deprecated.
|
|
48
|
-
> [4.8.
|
|
48
|
+
> [4.8.13 prepared](CHANGELOG.md) · [4.8.11 published](docs/releases/4.8.11.md) · [4.8.10](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
|
|
|
@@ -114,7 +114,7 @@ once you adopt. The other three are optional.
|
|
|
114
114
|
| **Before merge** | `arkgate-check` as a **required** CI status | Always (ArkGate) |
|
|
115
115
|
| **ArkRules** | Optional policies *inside* a layer | When you ask |
|
|
116
116
|
| **ArkRun** | Optional experimental runtime (`arkgate/runtime`) | Off unless you turn it on |
|
|
117
|
-
| **ArkOrder** | Stops
|
|
117
|
+
| **ArkOrder** | Stops rewriting a big product choice (like billing plan) as if it were a seat count. Change it through a valve, not a generic update (`arkgate/order`) | Off unless you turn it on |
|
|
118
118
|
|
|
119
119
|
Layers (who may import whom) always run. ArkRules, ArkRun, and ArkOrder change no
|
|
120
120
|
inter-layer verdict when absent. Label leftovers **`[Layer]`** vs **`[ArkRules]`** vs
|
|
@@ -231,7 +231,7 @@ expectation.
|
|
|
231
231
|
| Placement + preflight for multi-file changes | ✅ | ❌ |
|
|
232
232
|
| Honest governed % + dual plan (edges vs shape) | ✅ | ❌ |
|
|
233
233
|
| Opt-in intra-layer ArkRules (structure + invariants) | ✅ | ❌ |
|
|
234
|
-
| Stops
|
|
234
|
+
| Stops rewriting a big product choice like billing plan (ArkOrder) | ✅ | ❌ |
|
|
235
235
|
| Incomplete analysis cannot look green | ✅ | varies |
|
|
236
236
|
|
|
237
237
|
---
|
|
@@ -302,31 +302,20 @@ interfaces for production. Details: [docs/production-hardening.md](docs/producti
|
|
|
302
302
|
|
|
303
303
|
## Optional ArkOrder
|
|
304
304
|
|
|
305
|
-
Layers stop a bad import.
|
|
306
|
-
billing plan.
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
`refreshSigma`; ingest residual `absorb | escalate_up | hold` + `reasonCode`;
|
|
318
|
-
capacity pack as data; in-memory `ReleaseStore`; `ingestTravelAction`; ArkRun
|
|
319
|
-
`decisionTape`. A generic `update` of the plan does not land. A use-case that
|
|
320
|
-
PATCHes those keys through Prisma is named. Same npm package.
|
|
321
|
-
In-memory. Not durable. Does not replace ArkRun.
|
|
322
|
-
**ArkOrder freezes the pattern through a valve. ArkRun is how the residual travels.**
|
|
323
|
-
|
|
324
|
-
The billing gallery (`plan` / `cycle` / `tenancy`) lives on GitHub, not in the
|
|
325
|
-
npm tarball:
|
|
305
|
+
Layers stop a bad import. ArkOrder stops rewriting a big product choice — like
|
|
306
|
+
the billing plan — as if it were a seat count. Change those choices through a
|
|
307
|
+
valve, not a generic update.
|
|
308
|
+
|
|
309
|
+
Off unless you add `arkOrder`. Same npm package (`arkgate/order`). In-memory.
|
|
310
|
+
Not a service. Does not replace ArkGate or ArkRun.
|
|
311
|
+
|
|
312
|
+
Name the few choices (`xiKeys`: plan, cycle, tenancy — not seat counts). First
|
|
313
|
+
freeze is `release()`. Later change is `proposeRelease` then `apply`. A generic
|
|
314
|
+
`update` does not land.
|
|
315
|
+
|
|
316
|
+
The billing gallery lives on GitHub, not in the npm tarball:
|
|
326
317
|
[examples/arkorder-billing](https://github.com/pedroknigge/arkgate/tree/main/examples/arkorder-billing).
|
|
327
|
-
|
|
328
|
-
[ArkOrder](docs/arkorder.md) · [configuration](docs/configuration.md) ·
|
|
329
|
-
[package surface](docs/package-surface.md).
|
|
318
|
+
Compact starters leave it off. Details: [ArkOrder](docs/arkorder.md).
|
|
330
319
|
|
|
331
320
|
---
|
|
332
321
|
|
|
@@ -342,8 +331,10 @@ Rename the three keys. Compact starters leave it off. Details:
|
|
|
342
331
|
| Config · package surface · TS | [configuration](docs/configuration.md) · [package-surface](docs/package-surface.md) · [typescript-support](docs/typescript-support.md) |
|
|
343
332
|
| Brownfield | [docs/brownfield-adoption.md](docs/brownfield-adoption.md) |
|
|
344
333
|
| Security | [SECURITY.md](SECURITY.md) |
|
|
345
|
-
| Prepared (4.8.
|
|
346
|
-
| Current published (4.8.
|
|
334
|
+
| Prepared (4.8.13; not published) | [CHANGELOG](CHANGELOG.md) |
|
|
335
|
+
| Current published (4.8.11 on npm `latest`) | [docs/releases/4.8.11.md](docs/releases/4.8.11.md) · [CHANGELOG](CHANGELOG.md) |
|
|
336
|
+
| Prior published (4.8.10) | [docs/releases/4.8.10.md](docs/releases/4.8.10.md) · [CHANGELOG](CHANGELOG.md) |
|
|
337
|
+
| Prior published (4.8.9) | [docs/releases/4.8.9.md](docs/releases/4.8.9.md) · [CHANGELOG](CHANGELOG.md) |
|
|
347
338
|
| Prior published (4.8.7) | [docs/releases/4.8.7.md](docs/releases/4.8.7.md) · [CHANGELOG](CHANGELOG.md) |
|
|
348
339
|
| Prior published (4.8.6) | [docs/releases/4.8.6.md](docs/releases/4.8.6.md) |
|
|
349
340
|
| Prior published (4.8.5) | [docs/releases/4.8.5.md](docs/releases/4.8.5.md) |
|
|
@@ -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;
|
|
@@ -1815,6 +1821,7 @@ async function main() {
|
|
|
1815
1821
|
mode: fitness.mode,
|
|
1816
1822
|
improvementCompass: reportCompass,
|
|
1817
1823
|
arkRun: designDepth?.arkRun ?? null,
|
|
1824
|
+
arkOrder: designDepth?.arkOrder ?? null,
|
|
1818
1825
|
}),
|
|
1819
1826
|
leftoverDesignWork: designDepth?.designFitness?.designWeak === true,
|
|
1820
1827
|
};
|
|
@@ -1857,6 +1864,7 @@ async function main() {
|
|
|
1857
1864
|
? { deepModuleCoach: designDepth.deepModuleCoach }
|
|
1858
1865
|
: {}),
|
|
1859
1866
|
...(designDepth?.arkRun ? { arkRun: designDepth.arkRun } : {}),
|
|
1867
|
+
...(designDepth?.arkOrder ? { arkOrder: designDepth.arkOrder } : {}),
|
|
1860
1868
|
},
|
|
1861
1869
|
};
|
|
1862
1870
|
const html = args.beginner
|
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;
|
|
@@ -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
|
-
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GENERATED FILE — do not edit by hand.
|
|
3
|
+
*
|
|
4
|
+
* Canonical algorithm: src/domain/adapterFindingRefs.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-finding-refs.mjs). Zero Node I/O.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { ADAPTER_DIAGNOSTIC_DOCS_RELATIVE_PATH, } from './adapter-contract-types.mjs';
|
|
12
|
+
/**
|
|
13
|
+
* Baseline-compatible target key for a violation input.
|
|
14
|
+
* Field order and empty-string fallbacks **must** match `baselineKey` in
|
|
15
|
+
* `baselineKey.ts` — parity tests guard this so finding refs never orphan freezes.
|
|
16
|
+
*
|
|
17
|
+
* Note: uses raw ruleId/file strings (including empty) the same way baseline does;
|
|
18
|
+
* display `ruleId` / `location.file` may still normalize to ARK_UNKNOWN / `<unknown>`.
|
|
19
|
+
*/
|
|
20
|
+
export function adapterFindingTargetKey(violation) {
|
|
21
|
+
const ruleId = typeof violation.ruleId === 'string'
|
|
22
|
+
? violation.ruleId
|
|
23
|
+
: typeof violation.code === 'string'
|
|
24
|
+
? violation.code
|
|
25
|
+
: undefined;
|
|
26
|
+
const file = typeof violation.file === 'string' ? violation.file : undefined;
|
|
27
|
+
const fromLayer = typeof violation.fromLayer === 'string' ? violation.fromLayer : undefined;
|
|
28
|
+
const toLayer = typeof violation.toLayer === 'string' ? violation.toLayer : undefined;
|
|
29
|
+
const target = typeof violation.target === 'string' ? violation.target : undefined;
|
|
30
|
+
return [
|
|
31
|
+
ruleId,
|
|
32
|
+
file,
|
|
33
|
+
fromLayer ?? '',
|
|
34
|
+
toLayer ?? '',
|
|
35
|
+
target ?? '',
|
|
36
|
+
].join('|');
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Occurrence-aware target keys for a violation list (parity with baselineOccurrenceKeys).
|
|
40
|
+
* First occurrence keeps the historical base key; duplicates get `#N`.
|
|
41
|
+
*/
|
|
42
|
+
export function adapterFindingOccurrenceTargetKeys(violations) {
|
|
43
|
+
const counts = new Map();
|
|
44
|
+
return violations.map((violation) => {
|
|
45
|
+
const base = adapterFindingTargetKey(violation);
|
|
46
|
+
const occurrence = (counts.get(base) ?? 0) + 1;
|
|
47
|
+
counts.set(base, occurrence);
|
|
48
|
+
return occurrence === 1 ? base : `${base}#${occurrence}`;
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
/** FNV-1a finding ref from a baseline-compatible targetKey (not a security hash). */
|
|
52
|
+
export function adapterFindingRefFromTargetKey(targetKey) {
|
|
53
|
+
let hash = 0x811c9dc5;
|
|
54
|
+
for (let index = 0; index < targetKey.length; index += 1) {
|
|
55
|
+
hash ^= targetKey.charCodeAt(index);
|
|
56
|
+
hash = Math.imul(hash, 0x01000193);
|
|
57
|
+
}
|
|
58
|
+
return `fnv1a-${(hash >>> 0).toString(16).padStart(8, '0')}`;
|
|
59
|
+
}
|
|
60
|
+
/** Package-relative docs path with fragment for a public ruleId. */
|
|
61
|
+
export function adapterDocsCodePath(ruleId) {
|
|
62
|
+
return `${ADAPTER_DIAGNOSTIC_DOCS_RELATIVE_PATH}#${ruleId}`;
|
|
63
|
+
}
|