arkgate 4.8.8 → 4.8.10
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 +141 -3
- package/README.md +9 -6
- package/bin/ark-check-runtime.mjs +24 -2
- package/bin/ark-layer-match.mjs +25 -10
- package/bin/ark.mjs +18 -10
- package/bin/lib/agent-homes.mjs +1 -1
- package/bin/lib/analysis-engine.mjs +8 -8
- package/bin/lib/architecture-scan.mjs +91 -4
- package/bin/lib/ark-order-facts.mjs +11 -4
- package/bin/lib/ark-order-sensors.mjs +103 -3
- 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/config-extras.mjs +1 -0
- package/bin/lib/contract-smells.mjs +12 -6
- package/bin/lib/diagnostic-catalog.mjs +1 -0
- package/bin/lib/doctor-human.mjs +35 -10
- package/bin/lib/doctor-next-actions.mjs +24 -3
- package/bin/lib/field-install.mjs +23 -2
- package/bin/lib/first-run-help.mjs +69 -5
- package/bin/lib/gate-files.mjs +108 -22
- package/bin/lib/managed-upgrade.mjs +9 -1
- package/bin/lib/resolved-candidate-facts.mjs +82 -1
- package/bin/lib/rules-inventory.mjs +7 -3
- package/bin/lib/upgrade-command.mjs +17 -4
- package/bin/lib/upstream-report.mjs +330 -0
- package/bin/lib/violations.mjs +51 -15
- package/dist/{configTypes-0eHpocR3.d.ts → configTypes-j7so8B4O.d.ts} +12 -0
- package/dist/{diagnosticCatalog-DxKCTBbp.d.ts → diagnosticCatalog-biferT4R.d.ts} +11 -5
- package/dist/eslint/index.cjs +5 -8
- package/dist/eslint/index.d.ts +6 -4
- package/dist/eslint/index.js +5 -8
- package/dist/index.cjs +30 -33
- package/dist/index.d.ts +18 -6
- package/dist/index.js +30 -33
- package/dist/nestjs/index.cjs +3 -3
- package/dist/nestjs/index.d.ts +3 -3
- package/dist/nestjs/index.js +2 -2
- package/dist/order/index.cjs +1 -1
- package/dist/order/index.d.ts +6 -2
- package/dist/order/index.js +1 -1
- package/dist/runtime/index.cjs +11 -11
- package/dist/runtime/index.d.ts +6 -6
- package/dist/runtime/index.js +11 -11
- package/dist/{types-BK47clMl.d.ts → types-Djbs3KjE.d.ts} +1 -1
- package/dist/{types-DxvmJO-D.d.ts → types-tGhZUiGX.d.ts} +1 -1
- package/docs/README.md +4 -3
- package/docs/agent-guide.md +27 -2
- package/docs/ai-gates.md +8 -0
- package/docs/arkorder.md +30 -7
- package/docs/brownfield-adoption.md +30 -0
- package/docs/configuration.md +61 -14
- package/docs/develop.md +4 -2
- package/docs/diagnostics.md +10 -0
- package/docs/package-surface.md +7 -5
- package/docs/use.md +11 -0
- package/package.json +1 -1
- package/schemas/ark.config.schema.json +12 -2
- package/server.json +2 -2
- package/templates/agent-skills/README.md +1 -1
- package/templates/agent-skills/ark-contract/SKILL.md +1 -1
- package/templates/agent-skills/ark-explore/SKILL.md +24 -3
- package/templates/skills/ark-contract.md +1 -1
- package/templates/skills/ark-explore.md +24 -3
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,145 @@
|
|
|
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.10 — 2026-09-02
|
|
7
|
+
|
|
8
|
+
**Patch** over **4.8.9**. Amarilla first-aggregate sensors. Incomplete analysis
|
|
9
|
+
never looks green: an enforced sensor that cannot see its scope is not a pass.
|
|
10
|
+
**Write. Check. Ship.** **No required config migration.** No `schemaVersion` bump.
|
|
11
|
+
Does not close `K01` / `Z09`. No new skill names.
|
|
12
|
+
|
|
13
|
+
**Status: prepared** (tree candidate; npm `latest` remains **4.8.9** until the
|
|
14
|
+
signed-tag provenance workflow succeeds).
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
- `arkgate report` / `ark report` on the existing dual bins: draft an upstream GitHub issue for
|
|
18
|
+
`pedroknigge/arkgate` (`package.json` `bugs.url`), never the consumer repo. Default prints the
|
|
19
|
+
draft (arkgate version + last-check snippet). Create only with `--submit` and
|
|
20
|
+
`--i-confirm-submit` (or TTY `Type submit to send`). `--yes` does not submit. Missing or
|
|
21
|
+
unauthenticated `gh` prints the draft and the exact `gh issue create` command, then exits 2.
|
|
22
|
+
Not `ark-check --report` (HTML). Does not close `K01` / `Z09`. No new skill names.
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
- Structural-hint budget: when eligible governed files exceed `coverage.maxFiles`
|
|
26
|
+
(default `400`), emit `ARKRULE_HINT_BUDGET_EXHAUSTED` with exact hinted/governed
|
|
27
|
+
counts and per-sensor reviewed N/M of scope. `--strict-config` fails if an
|
|
28
|
+
enforced hint sensor is truncated. No `arkrules.hintBudget` key.
|
|
29
|
+
- `--update-baseline` GitHub rewrite touches only `ark-check` / `arkgate-check`
|
|
30
|
+
invocation lines (`run:` / package scripts). It does not append `--baseline` to
|
|
31
|
+
`concurrency.group` or job-id lines that merely name the check. Writes outside
|
|
32
|
+
the three law files are announced (`Synced --baseline into: …`).
|
|
33
|
+
- DomainModel class sensors: method finder is paren-balanced, so a later broken
|
|
34
|
+
method is visible. Remaining truncation is reported (`shape analysed until
|
|
35
|
+
character N`), not silent green.
|
|
36
|
+
- One shared invariant-word list (`ensureInvariants` / `raise` / `record` / `.push(`).
|
|
37
|
+
Assignment `=` is distinct from `===` / `!==` / `<=` / `>=`. `pendingEvents = []`
|
|
38
|
+
is idiomatic; events-array `.push(` counts as publish. Object literals and
|
|
39
|
+
multiline params are not public fields.
|
|
40
|
+
- `ARKRULE_SCOPE_EMPTY` is not freezable, even with `--force`. It is a config
|
|
41
|
+
diagnostic, not code debt. No `allowEmptyScope` key.
|
|
42
|
+
- `ARKRULE_STRUCTURE` freeze keys include the sensor id (and symbol when present).
|
|
43
|
+
A freeze for `orchestration-only` does not silence `thin-adapter` or
|
|
44
|
+
`writes-via-aggregate` on the same file. v1 empty-target keys remain exact-match
|
|
45
|
+
only.
|
|
46
|
+
- Intent-prefix checks apply only at declared intent-reference sites (`publish` /
|
|
47
|
+
`subscribe` / `defineIntent` / `registerHandler`, `intent` / `onEvent` /
|
|
48
|
+
`reactsTo`, publish `metadata.source`). Not every string literal. No
|
|
49
|
+
`kernel.dtypePrefixes`. A kernel DType such as `Management.EvmInspection.Data`
|
|
50
|
+
does not trip `LAYER_INTENT_REFERENCE_VIOLATION`.
|
|
51
|
+
- A5: `writes-via-aggregate` treats `@/lib/db` (and local `…/db`) as an IO import
|
|
52
|
+
without opening tsconfig. Write tokens require callee `db` / `tx` / `client` /
|
|
53
|
+
`prisma` / `drizzle`; `repo.update(` is not a write. Optional resolved-import
|
|
54
|
+
facts: PersistenceAdapters layer is a driver.
|
|
55
|
+
- IO import hints match `postgres` and `drizzle-orm/postgres-js` (package
|
|
56
|
+
subpaths), in lockstep for ArkRules and ArkOrder. `require()` matches the same
|
|
57
|
+
packages.
|
|
58
|
+
- React/UI `.set()` is not `ARKORDER_GENERIC_UPDATE`. Only `plane` /
|
|
59
|
+
`orderPlane` callees (or a file that constructs `createOrderPlane`) count as ξ
|
|
60
|
+
mutation. `Map` / `URLSearchParams` / `useState` setters stay silent.
|
|
61
|
+
- `--sensors` success is not a validity verdict. Stdout names the contract-only
|
|
62
|
+
skip (`Contract + coverage-evidence only: no TypeScript, no analysis. Not a
|
|
63
|
+
validity verdict.`); `--json` stamps `notAVerdict` / `didNotRun` /
|
|
64
|
+
`partialMode=contract-only`. It does not print `Ark check passed`.
|
|
65
|
+
|
|
66
|
+
### Changed
|
|
67
|
+
- `coverage.maxFiles` schema description, configuration docs, and diagnostics name
|
|
68
|
+
that the same budget also bounds structural-hint preload for `orchestration-only`,
|
|
69
|
+
`thin-adapter`, and `writes-via-aggregate`.
|
|
70
|
+
- Brownfield: law-then-product PR sequence when a rule’s folder does not exist yet
|
|
71
|
+
(advisory or placeholder path, then product, then promote). STRUCTURE key compat
|
|
72
|
+
for v1 empty-target rows is documented.
|
|
73
|
+
- A10: baseline regenerate note lists
|
|
74
|
+
`ark-check --update-baseline --force --contract-session --author <steward>`.
|
|
75
|
+
Doctor concentration looks at `sensor` / `arkruleId`; orchestration-only
|
|
76
|
+
majority is code debt, not “Fixing the contract”. Short `--help`: `--sensors`
|
|
77
|
+
does not run analysis; `--help --all` lists `--update-baseline` / `--author`.
|
|
78
|
+
AO11 9-vs-7 is not a bug.
|
|
79
|
+
- A11: `--changed` bounds file-local structural sensors and hint load to the
|
|
80
|
+
touched files. Import-edge, layer, and cycle sensors still see the full
|
|
81
|
+
governed graph. Optional process-local hint cache by content hash. Does not
|
|
82
|
+
claim 170s becomes seconds. No second analysis engine.
|
|
83
|
+
|
|
84
|
+
## 4.8.9 — 2026-09-01
|
|
85
|
+
|
|
86
|
+
**Patch** over **4.8.8**. Field diagnostic honesty: doctor default homedir, live
|
|
87
|
+
`peerIsolation` walls are not dead rules, skippable CI is `ci-not-fail-closed`
|
|
88
|
+
not `missing-gates`, blocked upgrade JSON carries `reasonCode` + `nextCommand`,
|
|
89
|
+
content identity vs raw `afterHash`, cross-layer `peerIsolation` docs, and
|
|
90
|
+
intent-reference checks share the import classifier. Amarilla ArkOrder:
|
|
91
|
+
`appliesTo`, watchlist vs `maxXiKeys`, `restore`, default clock, `hashOf`,
|
|
92
|
+
`.d.ts` honesty, packaged example URL, and ingest-payload honesty.
|
|
93
|
+
**No required config migration.** No `ark.config.json` schema bump. Does not close `K01` / `Z09`.
|
|
94
|
+
No new skill names.
|
|
95
|
+
|
|
96
|
+
**Status: published** (on npm `latest`; see `docs/releases/4.8.9.md`).
|
|
97
|
+
|
|
98
|
+
### Added
|
|
99
|
+
- Optional `arkOrder.appliesTo` globs (same engine as layers). `managedLayers`
|
|
100
|
+
still required; empty or absent `appliesTo` keeps today's all-files-in-layer
|
|
101
|
+
emit; a Persistence write outside the globs stays silent.
|
|
102
|
+
- `OrderPlane.restore(release)` installs a previously frozen `Release` (current
|
|
103
|
+
+ version). Hash remains the identity. Not durable. Does not close `K01`.
|
|
104
|
+
- Public `arkgate/order` exports `hashOf` (alias of `hashReleasePayload`) so a
|
|
105
|
+
stored `Release.hash` can be verified without calling `release()`.
|
|
106
|
+
|
|
107
|
+
### Fixed
|
|
108
|
+
- `--doctor` no longer throws when `CLAUDE_HOME` / `GROK_HOME` / `ANTIGRAVITY_HOME`
|
|
109
|
+
are unset (`skillsDirFor` now defaults `os.homedir()`).
|
|
110
|
+
- `contract-dead-rule` skips a live `peerIsolation` wall (`allowed: false` on a
|
|
111
|
+
same-layer or cross-layer pair). A self-allow stays dead. The fix text never
|
|
112
|
+
tells an agent to delete that wall.
|
|
113
|
+
- `--strict-merge` / `--require-gates` still fail skippable CI (`if:` other than
|
|
114
|
+
`true` / `always()`), but as `ci-not-fail-closed` (names the workflow file).
|
|
115
|
+
`missing-gates` remains only for files that are actually absent.
|
|
116
|
+
- Blocked `ark upgrade --apply --json` includes `reasonCode: managed-consent-required`
|
|
117
|
+
and a digest-bound `nextCommand` already carrying `--accept-conflicts`. Apply stays
|
|
118
|
+
atomic.
|
|
119
|
+
- `LAYER_INTENT_REFERENCE_VIOLATION` uses the same `peerIsolation` classifier as
|
|
120
|
+
imports (`fromPath` + `sharedRoots`). Shared-root files do not inherit the
|
|
121
|
+
slice-wall message. Cross-slice file imports still deny.
|
|
122
|
+
- Default `createOrderPlane` clock is Kernel `Date.now()` (was `0` with no
|
|
123
|
+
warning). Domain stays clock-free. Tests that need determinism still inject.
|
|
124
|
+
|
|
125
|
+
### Changed
|
|
126
|
+
- Public managed-upgrade assets expose `beforeIdentity` / `afterIdentity`.
|
|
127
|
+
`afterHash` is the SHA-256 of the raw desired bytes; `state: current` is content
|
|
128
|
+
identity, so stamp-only `arkVersion` drift can be current with unequal raw hashes.
|
|
129
|
+
- Docs: a slice wall on a cross-layer edge is a `peerIsolation` rule on that
|
|
130
|
+
`from`/`to` pair (`allowed: false`). Domain files without a slice fail-closed
|
|
131
|
+
unless listed in `sharedRoots`. No new engine mode, key, or skill.
|
|
132
|
+
- `maxXiKeys` caps one `release()` / `assertXiKeyCap` only. `xiKeys` is a
|
|
133
|
+
repo-wide watchlist; eight named keys with `maxXiKeys` 7 is valid config.
|
|
134
|
+
Sensor `arkorder-too-many-params` fires on `release()` `keyCount`, not on
|
|
135
|
+
config list length.
|
|
136
|
+
- Public `dist/order` `.d.ts` no longer says declarations-only / no runtime.
|
|
137
|
+
- Packaged docs point the billing gallery at the GitHub tree
|
|
138
|
+
(`https://github.com/pedroknigge/arkgate/tree/main/examples/arkorder-billing`).
|
|
139
|
+
The folder is not in the npm tarball; `examples/` is not added to
|
|
140
|
+
`package.json` `files`.
|
|
141
|
+
- Ingest payload-dependent escalation stays deliberate: `classifyIngest` uses
|
|
142
|
+
`kind`; `ConstraintPack` forbids user predicates. "Second week failing a
|
|
143
|
+
goal" is a domain/projector kind, not a pack function.
|
|
144
|
+
|
|
6
145
|
## 4.8.8 — 2026-09-01
|
|
7
146
|
|
|
8
147
|
**Patch** over **4.8.7**. ArkRun gains an opt-in terminal dashboard and bounded,
|
|
@@ -10,8 +149,7 @@ payload-free inspector monitors. ArkOrder and first-contact docs gain honesty co
|
|
|
10
149
|
**No required config migration.** No `ark.config.json` schema bump. Does not close
|
|
11
150
|
`K01` / `Z09`.
|
|
12
151
|
|
|
13
|
-
**Status:
|
|
14
|
-
signed-tag provenance workflow succeeds).
|
|
152
|
+
**Status: published** (see `docs/releases/4.8.8.md`).
|
|
15
153
|
|
|
16
154
|
### Added
|
|
17
155
|
- Dual **`ark-dashboard` / `arkgate-dashboard`** bins render the loopback ArkRun
|
|
@@ -40,7 +178,7 @@ show it when present. Caption-only edits do not change `policyHash`.
|
|
|
40
178
|
**No required config migration.** No `schemaVersion` bump. Does not close `K01` / `Z09`.
|
|
41
179
|
No new skill names.
|
|
42
180
|
|
|
43
|
-
**Status: published** (
|
|
181
|
+
**Status: published** (see `docs/releases/4.8.7.md`).
|
|
44
182
|
|
|
45
183
|
### Added
|
|
46
184
|
- Public name for existing `layers[].description`. Example:
|
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.10** is prepared on this tree; npm `latest` remains **4.8.9**.
|
|
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.10 prepared](docs/releases/4.8.10.md) · [4.8.9 published](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
|
|
|
@@ -321,8 +321,10 @@ PATCHes those keys through Prisma is named. Same npm package.
|
|
|
321
321
|
In-memory. Not durable. Does not replace ArkRun.
|
|
322
322
|
**ArkOrder freezes the pattern through a valve. ArkRun is how the residual travels.**
|
|
323
323
|
|
|
324
|
-
|
|
325
|
-
|
|
324
|
+
The billing gallery (`plan` / `cycle` / `tenancy`) lives on GitHub, not in the
|
|
325
|
+
npm tarball:
|
|
326
|
+
[examples/arkorder-billing](https://github.com/pedroknigge/arkgate/tree/main/examples/arkorder-billing).
|
|
327
|
+
Rename the three keys. Compact starters leave it off. Details:
|
|
326
328
|
[ArkOrder](docs/arkorder.md) · [configuration](docs/configuration.md) ·
|
|
327
329
|
[package surface](docs/package-surface.md).
|
|
328
330
|
|
|
@@ -340,8 +342,9 @@ three keys. Compact starters leave it off. Details:
|
|
|
340
342
|
| Config · package surface · TS | [configuration](docs/configuration.md) · [package-surface](docs/package-surface.md) · [typescript-support](docs/typescript-support.md) |
|
|
341
343
|
| Brownfield | [docs/brownfield-adoption.md](docs/brownfield-adoption.md) |
|
|
342
344
|
| Security | [SECURITY.md](SECURITY.md) |
|
|
343
|
-
| Prepared (4.8.
|
|
344
|
-
| Current published (4.8.
|
|
345
|
+
| Prepared (4.8.10; not published) | [docs/releases/4.8.10.md](docs/releases/4.8.10.md) · [CHANGELOG](CHANGELOG.md) |
|
|
346
|
+
| Current published (4.8.9 on npm `latest`) | [docs/releases/4.8.9.md](docs/releases/4.8.9.md) · [CHANGELOG](CHANGELOG.md) |
|
|
347
|
+
| Prior published (4.8.7) | [docs/releases/4.8.7.md](docs/releases/4.8.7.md) · [CHANGELOG](CHANGELOG.md) |
|
|
345
348
|
| Prior published (4.8.6) | [docs/releases/4.8.6.md](docs/releases/4.8.6.md) |
|
|
346
349
|
| Prior published (4.8.5) | [docs/releases/4.8.5.md](docs/releases/4.8.5.md) |
|
|
347
350
|
| Prior published (4.8.4) | [docs/releases/4.8.4.md](docs/releases/4.8.4.md) |
|
|
@@ -47,6 +47,7 @@ import {
|
|
|
47
47
|
REQUIRED_GATE_FILES,
|
|
48
48
|
detectWritePathCapabilities,
|
|
49
49
|
} from './lib/agent-gates.mjs';
|
|
50
|
+
import { ciNotFailClosed } from './lib/gate-files.mjs';
|
|
50
51
|
import { syncBaselineIntoCheckSurfaces } from './lib/field-install.mjs';
|
|
51
52
|
import {
|
|
52
53
|
detectEnforcement,
|
|
@@ -95,7 +96,7 @@ import {
|
|
|
95
96
|
writeArkRulesTemplates,
|
|
96
97
|
} from './lib/presets.mjs';
|
|
97
98
|
import { loadArkConfigContract, parseArkConfigJson } from './lib/config-contract.mjs';
|
|
98
|
-
import { checkUsage, checkUsageAll } from './lib/first-run-help.mjs';
|
|
99
|
+
import { checkUsage, checkUsageAll, withSensorsPartialModeHonesty } from './lib/first-run-help.mjs';
|
|
99
100
|
import { createAdapterResult } from './lib/adapter-contract.mjs';
|
|
100
101
|
import {
|
|
101
102
|
UNGOVERNED_PROBE_CAP,
|
|
@@ -1139,7 +1140,7 @@ async function main() {
|
|
|
1139
1140
|
|
|
1140
1141
|
if (args.sensors) {
|
|
1141
1142
|
const { runSensors } = await import('./lib/sensor-promote-cli.mjs');
|
|
1142
|
-
await runSensors(args, readConfig);
|
|
1143
|
+
await withSensorsPartialModeHonesty(args, () => runSensors(args, readConfig));
|
|
1143
1144
|
return;
|
|
1144
1145
|
}
|
|
1145
1146
|
|
|
@@ -1307,6 +1308,27 @@ async function main() {
|
|
|
1307
1308
|
process.exitCode = 1;
|
|
1308
1309
|
return;
|
|
1309
1310
|
}
|
|
1311
|
+
if (args.requireGates) {
|
|
1312
|
+
const ci = ciNotFailClosed(args.root);
|
|
1313
|
+
if (ci) {
|
|
1314
|
+
const payload = {
|
|
1315
|
+
ok: false,
|
|
1316
|
+
error: ci.error,
|
|
1317
|
+
message: ci.message,
|
|
1318
|
+
workflowFile: ci.workflowFile,
|
|
1319
|
+
nextAction: ci.nextAction,
|
|
1320
|
+
...(writeRequest?.host ? { writeHost: writeRequest.host } : {}),
|
|
1321
|
+
};
|
|
1322
|
+
if (args.json) {
|
|
1323
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
1324
|
+
} else {
|
|
1325
|
+
console.error(`${color.red('\u2716')} ${ci.error} ${ci.message}`);
|
|
1326
|
+
console.error(`Next: ${ci.nextAction}`);
|
|
1327
|
+
}
|
|
1328
|
+
process.exitCode = 1;
|
|
1329
|
+
return;
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1310
1332
|
// Gates present. This is a precondition, not a standalone report: stay quiet
|
|
1311
1333
|
// in --json mode so the architecture check below owns the single JSON output.
|
|
1312
1334
|
// When --require-gates is the only intent (no config/architecture run needed),
|
package/bin/ark-layer-match.mjs
CHANGED
|
@@ -362,15 +362,27 @@ export function crossSliceEdgeAllowed(allowedCrossSlice, fromSlice, toSlice) {
|
|
|
362
362
|
* Fail-closed stays fail-closed: absent evidence denies. What changed in 4.8.4
|
|
363
363
|
* is what counts as evidence — a declared shared root, or a declared directed
|
|
364
364
|
* cross-slice edge, is the repo telling us its design, so it is no longer
|
|
365
|
-
* "unclassifiable". Order: no
|
|
366
|
-
*
|
|
365
|
+
* "unclassifiable". Order: no fromPath → no slice folders → intent (no toPath):
|
|
366
|
+
* shared-root allow / slice fail-closed → a side that is neither in a slice nor
|
|
367
|
+
* declared shared → same slice → declared cross edge → deny.
|
|
368
|
+
*
|
|
369
|
+
* Intent/event names are not files. Callers pass fromPath only and must not
|
|
370
|
+
* invent a toPath (that would mis-slice). A declared shared root is classified
|
|
371
|
+
* the same way as on import edges.
|
|
367
372
|
*/
|
|
368
373
|
export function peerIsolationDecision(input) {
|
|
369
|
-
if (!input.fromPath
|
|
374
|
+
if (!input.fromPath)
|
|
370
375
|
return { denied: true, reason: 'missing-path' };
|
|
371
376
|
if (input.folderCount <= 0)
|
|
372
377
|
return { denied: true, reason: 'no-slice-folders' };
|
|
373
378
|
const fromClassified = Boolean(input.fromSlice) || input.fromShared === true;
|
|
379
|
+
if (!input.toPath) {
|
|
380
|
+
if (!fromClassified)
|
|
381
|
+
return { denied: true, reason: 'unclassifiable-path' };
|
|
382
|
+
if (!input.fromSlice)
|
|
383
|
+
return { denied: false };
|
|
384
|
+
return { denied: true, reason: 'missing-path' };
|
|
385
|
+
}
|
|
374
386
|
const toClassified = Boolean(input.toSlice) || input.toShared === true;
|
|
375
387
|
if (!fromClassified || !toClassified)
|
|
376
388
|
return { denied: true, reason: 'unclassifiable-path' };
|
|
@@ -387,8 +399,9 @@ export function peerIsolationDecision(input) {
|
|
|
387
399
|
/**
|
|
388
400
|
* Boolean face of {@link peerIsolationDecision}, kept for parity consumers.
|
|
389
401
|
*
|
|
390
|
-
* Fail-closed: missing
|
|
391
|
-
* side → deny.
|
|
402
|
+
* Fail-closed: missing fromPath, no classifiable folders, or unclassifiable
|
|
403
|
+
* either side → deny. Intent refs (no toPath) allow only a declared shared
|
|
404
|
+
* root. Same-slice → allow (return false). Cross-slice → deny unless the
|
|
392
405
|
* rule declared that directed edge.
|
|
393
406
|
*/
|
|
394
407
|
export function peerIsolationMustDeny(input) {
|
|
@@ -426,9 +439,11 @@ export function peerIsolationDenyExplanation(reason, context) {
|
|
|
426
439
|
* Same-layer is always allowed (historical short-circuit).
|
|
427
440
|
* - `peerIsolation: true` + `allowed: false`: deny only when importer and importee
|
|
428
441
|
* resolve to **different** slice ids (same or cross layer). Same-slice → allow.
|
|
429
|
-
*
|
|
430
|
-
*
|
|
431
|
-
*
|
|
442
|
+
* File imports pass fromPath + toPath. Intent references pass fromPath only.
|
|
443
|
+
* A declared shared root is classified (no denial). Missing fromPath, no slice
|
|
444
|
+
* folders, or unclassifiable slices → **fail-closed** (deny): isolation is
|
|
445
|
+
* configured, so insufficient evidence must not silently allow a possible
|
|
446
|
+
* cross-slice edge.
|
|
432
447
|
*/
|
|
433
448
|
export function findDeniedEdgeRule(rules, from, to, options) {
|
|
434
449
|
return findDeniedEdgeDecision(rules, from, to, options)?.rule;
|
|
@@ -448,8 +463,8 @@ export function findDeniedEdgeDecision(rules, from, to, options) {
|
|
|
448
463
|
const fromPath = options?.fromPath;
|
|
449
464
|
const toPath = options?.toPath;
|
|
450
465
|
const folders = resolveSliceFolders(rule, from, options?.layers);
|
|
451
|
-
const fromSlice = fromPath
|
|
452
|
-
const toSlice =
|
|
466
|
+
const fromSlice = fromPath ? sliceIdForPath(fromPath, folders) : undefined;
|
|
467
|
+
const toSlice = toPath ? sliceIdForPath(toPath, folders) : undefined;
|
|
453
468
|
const decision = peerIsolationDecision({
|
|
454
469
|
fromPath,
|
|
455
470
|
toPath,
|
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,
|
package/bin/lib/agent-homes.mjs
CHANGED
|
@@ -108,7 +108,7 @@ function usesDefaultHome(spec, env, homeDir) {
|
|
|
108
108
|
|
|
109
109
|
function skillsDirFor(host, env = process.env) {
|
|
110
110
|
const spec = HOSTS[host];
|
|
111
|
-
return path.join(resolveHomeDir(spec, env), 'skills');
|
|
111
|
+
return path.join(resolveHomeDir(spec, env, os.homedir()), 'skills');
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
function readHomeCatalogFloor(skillsDir) {
|