arkgate 4.8.20 → 4.8.21
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 +124 -5
- package/README.md +107 -117
- package/bin/ark-check-runtime.mjs +3 -4
- package/bin/ark-layer-match.mjs +110 -18
- package/bin/lib/analysis-engine.mjs +13 -6
- package/bin/lib/config-contract.mjs +5 -0
- package/bin/lib/diagnostic-catalog.mjs +1 -0
- package/bin/lib/doctor-advisories.mjs +20 -0
- package/bin/lib/doctor-human.mjs +11 -9
- package/bin/lib/doctor-plan.mjs +15 -14
- package/bin/lib/first-run-help.mjs +7 -1
- package/bin/lib/html-report-advisories.mjs +8 -0
- package/bin/lib/html-report-depth.mjs +9 -8
- package/bin/lib/invariant-coverage.mjs +396 -75
- package/bin/lib/managed-upgrade.mjs +59 -14
- package/bin/lib/pilot-loop.mjs +183 -37
- package/bin/lib/upgrade-behavior-changes.mjs +83 -0
- package/bin/lib/upgrade-command.mjs +69 -31
- package/bin/lib/upgrade-outcome.mjs +359 -0
- package/bin/lib/violations.mjs +109 -0
- package/dist/{configTypes-VVknqcTJ.d.ts → configTypes-CTELo87-.d.ts} +7 -0
- package/dist/{diagnosticCatalog-BPYWNyJR.d.ts → diagnosticCatalog-B7BXlet6.d.ts} +73 -5
- package/dist/eslint/index.cjs +4 -4
- package/dist/eslint/index.d.ts +26 -3
- package/dist/eslint/index.js +4 -4
- package/dist/index.cjs +24 -17
- package/dist/index.d.ts +9 -4
- package/dist/index.js +25 -18
- package/dist/nestjs/index.cjs +9 -9
- package/dist/nestjs/index.d.ts +3 -3
- package/dist/nestjs/index.js +9 -9
- package/dist/runtime/index.cjs +18 -11
- package/dist/runtime/index.d.ts +6 -6
- package/dist/runtime/index.js +18 -11
- package/dist/{types-p_fCp6P-.d.ts → types-fQ9-KrBj.d.ts} +1 -1
- package/dist/{types-Cs-46DRu.d.ts → types-yDNEQ603.d.ts} +1 -1
- package/docs/README.md +4 -3
- package/docs/agent-guide.md +15 -7
- package/docs/brownfield-adoption.md +4 -3
- package/docs/configuration.md +34 -11
- package/docs/diagnostics.md +12 -2
- package/docs/package-surface.md +3 -2
- package/docs/product-voice.md +11 -3
- package/package.json +1 -1
- package/schemas/ark.config.schema.json +8 -0
- package/server.json +2 -2
- package/templates/agent-skills/README.md +1 -1
- package/templates/agent-skills/ark-adopt/SKILL.md +5 -2
- package/templates/agent-skills/ark-architect/SKILL.md +2 -0
- package/templates/agent-skills/ark-autopilot/SKILL.md +6 -4
- package/templates/agent-skills/ark-contract/SKILL.md +2 -0
- package/templates/agent-skills/ark-coverage/SKILL.md +2 -0
- package/templates/agent-skills/ark-explain/SKILL.md +2 -0
- package/templates/agent-skills/ark-explore/SKILL.md +4 -2
- package/templates/agent-skills/ark-fix/SKILL.md +2 -0
- package/templates/agent-skills/ark-loop/SKILL.md +2 -0
- package/templates/agent-skills/ark-order/SKILL.md +2 -0
- package/templates/agent-skills/ark-place/SKILL.md +2 -0
- package/templates/agent-skills/ark-runtime/SKILL.md +2 -0
- package/templates/agent-skills/ark-think/SKILL.md +2 -0
- package/templates/agent-skills/ark-upgrade/SKILL.md +20 -7
- package/templates/skills/ark-adopt.md +5 -2
- package/templates/skills/ark-architect.md +2 -0
- package/templates/skills/ark-autopilot.md +6 -4
- package/templates/skills/ark-contract.md +2 -0
- package/templates/skills/ark-coverage.md +2 -0
- package/templates/skills/ark-explain.md +2 -0
- package/templates/skills/ark-explore.md +4 -2
- package/templates/skills/ark-fix.md +2 -0
- package/templates/skills/ark-loop.md +2 -0
- package/templates/skills/ark-order.md +2 -0
- package/templates/skills/ark-place.md +2 -0
- package/templates/skills/ark-runtime.md +2 -0
- package/templates/skills/ark-think.md +2 -0
- package/templates/skills/ark-upgrade.md +20 -7
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as Policy, P as PolicyViolation, I as IntentName, j as IntentCreator, k as IntentRelationship, b as ArchitectureProfile, D as DomainEvent, E as EventMetadata, h as PolicyEnforcementMode, A as ArchitectureLayer, c as ArchitectureRule, d as ArkCheckConfig } from './types-
|
|
1
|
+
import { i as Policy, P as PolicyViolation, I as IntentName, j as IntentCreator, k as IntentRelationship, b as ArchitectureProfile, D as DomainEvent, E as EventMetadata, h as PolicyEnforcementMode, A as ArchitectureLayer, c as ArchitectureRule, d as ArkCheckConfig } from './types-fQ9-KrBj.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* PolicyEngine
|
package/docs/README.md
CHANGED
|
@@ -73,12 +73,13 @@ These are **not** the day-to-day product path. They stay in the repo for evidenc
|
|
|
73
73
|
| Field adoption kit (scaffolding, not closed) | [field/](field/) |
|
|
74
74
|
| Runtime hardening (experimental) | [production-hardening.md](production-hardening.md) |
|
|
75
75
|
|
|
76
|
-
Current
|
|
76
|
+
Current release: [CHANGELOG](../CHANGELOG.md) (`arkgate@4.8.21`; confirm npm with `npm view arkgate@4.8.21 version`; does not close `K01`).
|
|
77
|
+
Prior published: [CHANGELOG](../CHANGELOG.md) (`arkgate@4.8.20`). Plain-English history: [arkgate.online/changelog](https://www.arkgate.online/changelog/).
|
|
77
78
|
Prior published: [releases/4.8.11.md](releases/4.8.11.md) (`arkgate@4.8.11`).
|
|
78
79
|
Prior published: [releases/4.8.10.md](releases/4.8.10.md) (`arkgate@4.8.10`).
|
|
79
80
|
Prior published: [releases/4.8.9.md](releases/4.8.9.md) (`arkgate@4.8.9`).
|
|
80
|
-
Prior: [releases/4.8.6.md](releases/4.8.6.md) · [releases/4.8.5.md](releases/4.8.5.md) · [releases/4.8.4.md](releases/4.8.4.md) · [releases/4.8.3.md](releases/4.8.3.md) · [releases/4.8.2.md](releases/4.8.2.md) · [releases/4.8.1.md](releases/4.8.1.md) · [4.8.0](releases/4.8.0.md) · [4.7.6](releases/4.7.6.md) · [4.7.5](releases/4.7.5.md) · [4.7.4](releases/4.7.4.md) · [4.7.3](releases/4.7.3.md) · [4.7.2](releases/4.7.2.md) · [4.7.1](releases/4.7.1.md) · [4.7.0](releases/4.7.0.md) · [4.6.7](releases/4.6.7.md) · [4.6.6](releases/4.6.6.md) · [4.6.5](releases/4.6.5.md) · [4.6.4](releases/4.6.4.md) · [4.6.3](releases/4.6.3.md) · [4.6.2](releases/4.6.2.md) · [4.6.1](releases/4.6.1.md) · [4.6.0](releases/4.6.0.md).
|
|
81
|
-
Older notes: [releases/](releases/). Config: [configuration.md](configuration.md).
|
|
81
|
+
Prior: [releases/4.8.8.md](releases/4.8.8.md) · [releases/4.8.7.md](releases/4.8.7.md) · [releases/4.8.6.md](releases/4.8.6.md) · [releases/4.8.5.md](releases/4.8.5.md) · [releases/4.8.4.md](releases/4.8.4.md) · [releases/4.8.3.md](releases/4.8.3.md) · [releases/4.8.2.md](releases/4.8.2.md) · [releases/4.8.1.md](releases/4.8.1.md) · [4.8.0](releases/4.8.0.md) · [4.7.6](releases/4.7.6.md) · [4.7.5](releases/4.7.5.md) · [4.7.4](releases/4.7.4.md) · [4.7.3](releases/4.7.3.md) · [4.7.2](releases/4.7.2.md) · [4.7.1](releases/4.7.1.md) · [4.7.0](releases/4.7.0.md) · [4.6.7](releases/4.6.7.md) · [4.6.6](releases/4.6.6.md) · [4.6.5](releases/4.6.5.md) · [4.6.4](releases/4.6.4.md) · [4.6.3](releases/4.6.3.md) · [4.6.2](releases/4.6.2.md) · [4.6.1](releases/4.6.1.md) · [4.6.0](releases/4.6.0.md).
|
|
82
|
+
Older notes: [releases/4.5.7.md](releases/4.5.7.md) · [releases/4.5.6.md](releases/4.5.6.md) · [releases/4.5.5.md](releases/4.5.5.md) · [releases/](releases/). Config: [configuration.md](configuration.md).
|
|
82
83
|
|
|
83
84
|
---
|
|
84
85
|
|
package/docs/agent-guide.md
CHANGED
|
@@ -161,6 +161,8 @@ npx arkgate upgrade --apply # registry-aware package step, then re-previ
|
|
|
161
161
|
npx arkgate upgrade --apply --no-install --plan-digest sha256:… --refresh-skills
|
|
162
162
|
```
|
|
163
163
|
|
|
164
|
+
`upgrade --apply` exits `0` when the managed files were applied and the architecture check is green, `3` when they were applied but the check is red, `2` when a recorded file still needs consent, and `1` on error (including a stale plan digest). Scripts comparing the status against `1` must switch to non-zero. JSON adds `outcome` and `postUpgrade` (`verdict`, `failing[{ruleId,count,sample}]`, `behaviorChanges`). `behaviorChanges` is the shipped per-version table, the same sentences as the changelog migration notes. A missing gitignored managed file is `absent-local` and is recreated without `--accept-conflicts`. Every blocked asset has `reason` and `nextCommand`. If `postUpgrade.verdict` is `red`, stop: report `failing` and `behaviorChanges`, and do not edit tests, titles, or config in that turn.
|
|
165
|
+
|
|
164
166
|
### Two-axis done recipe
|
|
165
167
|
|
|
166
168
|
Architecture residual and feature residual are **separate axes**. Never collapse them:
|
|
@@ -361,13 +363,16 @@ npx ark-check --doctor --fail-on-new-smells --base-ref origin/main --json # opt-
|
|
|
361
363
|
(`clarify-for-ai`) — **one** Shape door: `/ark-explore` shape-focus → dual-plan B, then
|
|
362
364
|
`/ark-autopilot` applies one pilot. Do not skill-shop coverage/think for the same residual.
|
|
363
365
|
|
|
364
|
-
**Pilot loop (Q04):**
|
|
365
|
-
|
|
366
|
+
**Pilot loop (Q04):** `pilotLoop` is active when a pilot candidate exists. Design-weak
|
|
367
|
+
pattern bets are one source. A proposed physical-cohesion reshape card is the other, even
|
|
368
|
+
when the tree is not design-weak. `pilotLoop.nextPilot` / `extractionCard` is **one**
|
|
369
|
+
extraction card (pilot target, move, success, kill-switch). Apply **that one pilot only**,
|
|
370
|
+
then re-doctor. Further candidates stay queued. Inactive reason is `no-pilot-candidates`.
|
|
366
371
|
Success = reduced smell evidence on pilot paths; residual outside the pilot may remain.
|
|
367
372
|
Never select seed/fixture/demo/migration/generated files as god-module pilots. A real UI business
|
|
368
373
|
rule moves Domain → Application → UI; local permission/UI-state helpers are not selected by their
|
|
369
374
|
`canEdit`-style name alone. Never multi-pilot batch; never mechanical-safe; never claim healthy
|
|
370
|
-
finished while
|
|
375
|
+
finished while `doctor.productHonesty.finished` is false.
|
|
371
376
|
|
|
372
377
|
**AI-velocity evidence (Q05):** deterministic fixture bench (no live LLM) compares the same
|
|
373
378
|
feature add on design-weak vs golden-path trees. Run `npm run eval:ai-velocity`; metric is
|
|
@@ -432,9 +437,11 @@ port. Advisory only — never blocks, never feeds `designFitness`; no strict mod
|
|
|
432
437
|
clusters per anchor directory (concentration, not volume — dispersed hooks never fire) with
|
|
433
438
|
fixed corpus-calibrated thresholds; anchors under `app/`/`pages/` are `fixedByConvention` and
|
|
434
439
|
never move. `reshapePilot.nextPilot` is a **proposed** one-at-a-time card (`moveSample`,
|
|
435
|
-
`movesTotal`, `successSignal`, `killSwitch`, `doNot[]`)
|
|
436
|
-
|
|
437
|
-
|
|
440
|
+
`movesTotal`, `successSignal`, `killSwitch`, `doNot[]`) and, when proposed, the single
|
|
441
|
+
`pilotLoop` extraction card if no design-weak pattern bet is ahead of it. Run it only via
|
|
442
|
+
`/ark-loop` through the write gate + atomic preflight; merges are `/ark-adopt` /
|
|
443
|
+
`/ark-autopilot` judgment cards. `notAScore`, never a verdict/`designFitness` input; there
|
|
444
|
+
is no apply path.
|
|
438
445
|
|
|
439
446
|
**Reshape decision memory (Y01):** when the team accepts, defers, or rejects that target, record
|
|
440
447
|
the explicit verdict in `.ark/reshape-decisions.json` using the card's exact
|
|
@@ -1135,7 +1142,8 @@ edges are not denied by that rule.
|
|
|
1135
1142
|
|
|
1136
1143
|
- **Denied:** `src/features/auth/**` → `src/features/payments/**` (different slice id).
|
|
1137
1144
|
- **Allowed:** same-slice imports when both paths classify; classic non-peerIsolation denies still apply across layers.
|
|
1138
|
-
- **`sliceFolders`:** optional parent segments (default: inferred from layer globs).
|
|
1145
|
+
- **`sliceFolders`:** optional parent segments (default: inferred from layer globs). A bare name stays an unanchored one-segment match (`features` on `src/features/auth` is `features/auth`). A starred anchored pattern with `sliceIdentity` `path` (the default) includes the literal prefix plus the star bindings (`lib/features/*/*` → `lib/features/projects/rfi`), so parallel trees get different ids.
|
|
1146
|
+
- **`sliceIdentity`:** `path` (default, also when the key is absent) or `stars`. `path` keeps today's slice ids. `stars` names a starred prefix as the last literal plus the star bindings (`lib/features/*/*` and `lib/repositories/features/*/*` both yield `features/projects/rfi`). Doctor names both prefixes when they collapse onto one id. Additive — no migration.
|
|
1139
1147
|
- **Fail-closed:** missing paths, empty/unresolvable slice folders, or unclassifiable either side → **deny** via peerIsolation (cannot prove same-slice).
|
|
1140
1148
|
- **`sharedRoots`** (4.8.4): roots the repo declares shared on purpose (`["ui", "hooks", "lib/permissions"]`). A file under a declared shared root is evidence, not an unclassifiable path, so fail-closed stops firing on every shared file. **Anchored** — the root starts the path, optionally after one `src/` or `app/`; write deeper or monorepo roots out (`packages/web/src/ui`) or glob them, and a bare `*` / `**` is refused. A path that still resolves to a slice keeps its slice.
|
|
1141
1149
|
- **`allowedCrossSlice`** (4.8.4): `[{ "from": "features/checkout", "to": "features/catalog" }]` — one directed slice→slice edge the repo declares on purpose. The reverse still denies.
|
|
@@ -228,12 +228,13 @@ ark-check --plan --json # patternBets[] with neverMechanicalSafe: true
|
|
|
228
228
|
|
|
229
229
|
### Pilot loop (Q04) — one pilot at a time → re-doctor
|
|
230
230
|
|
|
231
|
-
When
|
|
231
|
+
When a pilot candidate exists, doctor/plan JSON includes **`pilotLoop`**:
|
|
232
232
|
|
|
233
233
|
| Field | Meaning |
|
|
234
234
|
|-------|---------|
|
|
235
|
-
| `pilotLoop.active` | `true` when design-weak
|
|
236
|
-
| `pilotLoop.nextPilot` | **One** extraction card (same fields as §6)
|
|
235
|
+
| `pilotLoop.active` | `true` when a candidate exists: a design-weak pattern bet, or a proposed reshape card |
|
|
236
|
+
| `pilotLoop.nextPilot` / `extractionCard` | **One** extraction card (same fields as §6). Further candidates stay queued |
|
|
237
|
+
| `pilotLoop.reason` | `no-pilot-candidates` when the list is empty |
|
|
237
238
|
| `pilotLoop.oneAtATime` | Always true — do not multi-pilot batch |
|
|
238
239
|
| `pilotLoop.neverMechanicalSafe` | Always true — judgment only; re-doctor is the success sensor |
|
|
239
240
|
|
package/docs/configuration.md
CHANGED
|
@@ -250,8 +250,8 @@ process module-capability family must be denied.
|
|
|
250
250
|
|
|
251
251
|
Rule fields:
|
|
252
252
|
|
|
253
|
-
- `from`, `to`, `allowed`, `message`, `peerIsolation`, `sliceFolders`, `
|
|
254
|
-
`allowedCrossSlice`, `sharedImportsSlice`
|
|
253
|
+
- `from`, `to`, `allowed`, `message`, `peerIsolation`, `sliceFolders`, `sliceIdentity`,
|
|
254
|
+
`sharedRoots`, `allowedCrossSlice`, `sharedImportsSlice`
|
|
255
255
|
- `peerIsolation: true` + `allowed: false`: deny only when slice ids differ; same-slice allows
|
|
256
256
|
when both paths classify. Applies to **any** declared `from`→`to` pair, not only self-edges.
|
|
257
257
|
Missing paths, empty slice folders, or unclassifiable slices **fail closed** (deny — cannot
|
|
@@ -262,15 +262,38 @@ Rule fields:
|
|
|
262
262
|
`src/components/features/projects/rfi-status-pill.tsx` with `["projects"]` is not a slice.
|
|
263
263
|
A starred prefix (`lib/features/*/*`) is anchored like `sharedRoots` — it starts the
|
|
264
264
|
repo-relative path, or sits one segment in after `src/` or `app/`. Each `*` binds one
|
|
265
|
-
directory and never the filename.
|
|
266
|
-
|
|
267
|
-
`lib/features/projects
|
|
265
|
+
directory and never the filename. With `sliceIdentity` `path` (the default, also
|
|
266
|
+
when the key is absent) the slice id includes the literal prefix plus those
|
|
267
|
+
star bindings (`lib/features/projects/rfi`), so parallel trees get different ids.
|
|
268
|
+
A file directly under `lib/features/projects/` stays `lib/features/projects`. A path
|
|
269
|
+
off that prefix (`src/app/api/projects/...`) is not that slice.
|
|
270
|
+
- `sliceIdentity` is `path` or `stars`. Absent and `path` are the same: today's ids,
|
|
271
|
+
byte for byte, so baselines and `allowedCrossSlice` keep working with no migration.
|
|
272
|
+
`stars` names a starred prefix as the last literal plus the star bindings.
|
|
273
|
+
`lib/features/*/*` and `lib/repositories/features/*/*` both yield
|
|
274
|
+
`features/projects/rfi`, so one feature has one id across parallel trees. Bare names
|
|
275
|
+
(`features`) are unchanged. Doctor warns when two different prefixes bind as the
|
|
276
|
+
same id, and the warning names both paths (`admin/features/*` and `public/features/*`
|
|
277
|
+
both bind as `features/*`). That warning is advisory. Unrelated trees that share a
|
|
278
|
+
last folder name should stay on `path`.
|
|
279
|
+
|
|
280
|
+
```jsonc
|
|
281
|
+
{
|
|
282
|
+
"from": "ApplicationOrchestration",
|
|
283
|
+
"to": "PersistenceAdapters",
|
|
284
|
+
"allowed": false,
|
|
285
|
+
"peerIsolation": true,
|
|
286
|
+
"sliceFolders": ["lib/features/*/*", "lib/repositories/features/*/*"],
|
|
287
|
+
"sliceIdentity": "stars"
|
|
288
|
+
}
|
|
289
|
+
```
|
|
268
290
|
|
|
269
291
|
#### Cross-layer slice walls (already in the engine)
|
|
270
292
|
|
|
271
293
|
A slice wall on a cross-layer edge is a `peerIsolation` rule on that `from`/`to` pair
|
|
272
|
-
(`allowed: false`). There is no slice-wide engine mode
|
|
273
|
-
|
|
294
|
+
(`allowed: false`). There is no slice-wide engine mode and no new skill name.
|
|
295
|
+
`sliceIdentity` only changes how a starred prefix is named. `findDeniedEdgeDecision`
|
|
296
|
+
already applies `peerIsolation` to any declared pair
|
|
274
297
|
(same-layer or cross-layer) — locked on `EdgeRule` and `findDeniedEdgeDecision` in
|
|
275
298
|
[`src/domain/layerMatch.ts`](../src/domain/layerMatch.ts). There is no dedicated ADR to add.
|
|
276
299
|
|
|
@@ -320,9 +343,9 @@ is evidence:
|
|
|
320
343
|
character must not disable fail-closed. A path that still resolves to a slice keeps its slice —
|
|
321
344
|
`features/auth/ui/form.tsx` stays `features/auth`. Shared roots are a sink: a slice may import
|
|
322
345
|
a shared root, and a shared root may import a slice unless the rule sets `sharedImportsSlice`
|
|
323
|
-
to `"deny"`. That hop is direct only — `allowedCrossSlice` does not excuse it.
|
|
324
|
-
|
|
325
|
-
direct-only.
|
|
346
|
+
to `"deny"`. That hop is direct only — `allowedCrossSlice` does not excuse it. A green
|
|
347
|
+
`ark-check` prints one line per layer edge (the count and three examples) and says the
|
|
348
|
+
wall is direct-only. Every edge stays in `ark-check --json` and `ark-check --doctor`.
|
|
326
349
|
- `allowedCrossSlice` entries match a full slice id (`features/catalog`) or a bare slice name
|
|
327
350
|
(`catalog`), and only in the direction written. The reverse edge still denies. A bare name
|
|
328
351
|
matches that name under **any** slice folder, so in a repo with several slice parents
|
|
@@ -413,7 +436,7 @@ Each `arkrules/<Layer>.json` may declare:
|
|
|
413
436
|
| Section | Purpose | Modes | What it really enforces |
|
|
414
437
|
|---------|---------|--------|-------------------------|
|
|
415
438
|
| `structure[]` | Closed sensor ids (e.g. `orchestration-only`, `thin-adapter`, `writes-via-aggregate`, `aggregate-private-state`, `always-valid-factory`, `domain-event-on-mutation`, `no-anemic-model`) | `advisory` (default) or `enforced` | **Heuristics of module shape** — not proof that logic was extracted to Domain. `writes-via-aggregate` is driver-import + write-token in the declaring layer (ADR 0032). Tier-2 sensors (`no-anemic-model`) stay advisory-only (cannot promote to enforced). |
|
|
416
|
-
| `invariants[]` | Stable ids + description + `coverage` (`test` / `symbol`) + optional `appliesTo` globs | `advisory` or `enforced` | **Named policy + evidence.** `coverage.symbol` means a declaration of that identifier in a non-test file (witness path `symbolEvidenceFile`)
|
|
439
|
+
| `invariants[]` | Stable ids + description + `coverage` (`test` / `symbol`) + optional `appliesTo` globs | `advisory` or `enforced` | **Named policy + evidence.** `coverage.symbol` means a declaration of that identifier in a non-test file (witness path `symbolEvidenceFile`; additive `shape`: `function`, `class`, `const`, `method`, `type`, `interface`, or `enum`). Imports and test calls do not count. A `describe` / `it` / `test` / `context` title may also name the invariant id. A comment, string, or other bare mention does not. Does **not** execute tests or business logic and does **not** replace behavior/property tests. Doctor and `--rules-inventory` print the witness path and discard counts on green runs too. A declaration match is not “the tests pass.” |
|
|
417
440
|
|
|
418
441
|
**Reporting:** diagnostics carry `evidence.arkruleId` + `evidence.arkruleSource`. Label residual
|
|
419
442
|
**`[Layer]`** vs **`[ArkRules]`** in agent output. Doctor / HTML: `rulesUnderContract` (catalog +
|
package/docs/diagnostics.md
CHANGED
|
@@ -101,6 +101,7 @@ Link form for agents: `docs/diagnostics.md#RULE_ID` (exact-case HTML anchors bel
|
|
|
101
101
|
| [`CONFIG_AMBIGUOUS_LAYERS`](#CONFIG_AMBIGUOUS_LAYERS) | config | Ambiguous layer classification |
|
|
102
102
|
| [`CONFIG_UNCLASSIFIED_FILES`](#CONFIG_UNCLASSIFIED_FILES) | config | Unclassified included files |
|
|
103
103
|
| [`CONFIG_LAYER_MISSING_OWNER`](#CONFIG_LAYER_MISSING_OWNER) | config | Layer missing owner |
|
|
104
|
+
| [`CONFIG_SLICE_IDENTITY_COLLISION`](#CONFIG_SLICE_IDENTITY_COLLISION) | config | Starred slice prefixes share one id |
|
|
104
105
|
| [`ARK_UNKNOWN`](#ARK_UNKNOWN) | meta | Unknown diagnostic |
|
|
105
106
|
|
|
106
107
|
## Layer and dependency graph
|
|
@@ -308,8 +309,8 @@ Link form for agents: `docs/diagnostics.md#RULE_ID` (exact-case HTML anchors bel
|
|
|
308
309
|
|
|
309
310
|
**Invariant without coverage evidence**
|
|
310
311
|
|
|
311
|
-
- **Why:** An ArkRules invariant is under contract but no covering test title or declared symbol evidence was found (or coverage is partial). Kind is `never-had-tests` (adopt residual) vs `tests-disappeared` (suite exists).
|
|
312
|
-
- **Fix:**
|
|
312
|
+
- **Why:** An ArkRules invariant is under contract but no covering test title or declared symbol evidence was found (or coverage is partial). A title is a `describe` / `it` / `test` / `context` string. A comment, string, test body, or import that only mentions the id does not count. `coverage.symbol` is a non-test declaration: `function`, `class`, `const`, `method`, `type`, `interface`, or `enum`. Kind is `never-had-tests` (adopt residual) vs `tests-disappeared` (suite exists). The message names what the scan found.
|
|
313
|
+
- **Fix:** Put the invariant id in a `describe` / `it` title, or declare the `coverage.symbol` name in a non-test file, then preflight again. A comment is not a title — move the id into the `it()` title. Treat never-had-tests as adopt residual; treat tests-disappeared as a regression. Missing test globs report partial — never fake green. When the message reports an exhausted file budget, raise `coverage.maxFiles` (or narrow `coverage.testGlobs`) in ark.config.json. The message also names every file the scan discarded and why (budget, per-file byte cap, unreadable, walk depth limit, symlink resolving outside the project root, no catalogued invariant named) — nothing is dropped in silence.
|
|
313
314
|
|
|
314
315
|
<a id="INVARIANT_COVERAGE_OUTSIDE_ROOTS"></a>
|
|
315
316
|
|
|
@@ -894,6 +895,15 @@ never opting out of knowing.
|
|
|
894
895
|
- **Why:** `requireLayerOwners` is on and this layer has no owners. Writes to that house fail closed, like a folder with no name on the door.
|
|
895
896
|
- **Fix:** Add a GitHub handle or email to that layer’s owners in ark.config.json (`/ark-adopt`), then re-run. Reserved/allowEmpty houses may stay unnamed.
|
|
896
897
|
|
|
898
|
+
<a id="CONFIG_SLICE_IDENTITY_COLLISION"></a>
|
|
899
|
+
|
|
900
|
+
### `CONFIG_SLICE_IDENTITY_COLLISION`
|
|
901
|
+
|
|
902
|
+
**Starred slice prefixes share one id**
|
|
903
|
+
|
|
904
|
+
- **Why:** `sliceIdentity` is `stars` and two different `sliceFolders` prefixes bind as the same slice id. Parallel trees of one feature do that on purpose; unrelated trees that share the last folder name merge by accident. The warning names both paths.
|
|
905
|
+
- **Fix:** Keep `stars` when those prefixes are one feature. Otherwise use `path`, or rename the last literal so the prefixes do not bind as the same id. Advisory — it does not fail the check.
|
|
906
|
+
|
|
897
907
|
## Meta
|
|
898
908
|
|
|
899
909
|
<a id="ARK_UNKNOWN"></a>
|
package/docs/package-surface.md
CHANGED
|
@@ -48,12 +48,13 @@ hardening guide remains repository-hosted rather than duplicated in the gate tar
|
|
|
48
48
|
| **ArkRun doctor / status / report (RN08)** | `ark-check --doctor --json` → `doctor.arkRun`; HTML `data-advisory="arkRun"`; `ark status --json` / MCP `ark_status` → `arkRun`; `rulesUnderContract.mergePlanes.arkRun` | Additive. Always **`notAScore: true`**. Residual is a finding-id count (status residual `null` = unknown, not green). Advisory and absence never arm extra merge teeth; enforced teeth follow the classified-layer floor. Never a score or LLM verdict. |
|
|
49
49
|
| **Upgrade what’s new (4.5.6+)** | `ark upgrade --json` → `whatsNew` (+ human **Suggested improvements** block; also on preview). | Always **`notAScore: true`**, **`neverGateInput: true`**. Closed try/inspect list: deep-module coach, improvement compass, session/status honesty, two-axis done, self-service honesty, registry-aware upgrade, skill drift/refresh, multi-project MCP, Codex hard-write refresh/trust/restart/verify, stale MCP/global CLI recovery. Never invents residual or flips gates. |
|
|
50
50
|
| **Field upgrade truth (4.5.6)** | `ark upgrade` registry-aware install; JSON `reasonCode` / `suggestedInstallCmd`; `skillDrift`; `--refresh-skills`; `postUpgradeChecks`; `hostSelection`. | No false-skip when registry ahead; offline honesty; customized skills preserved unless opt-in refresh; checks are advisory only. |
|
|
51
|
+
| **Upgrade outcome (4.8.21)** | `ark upgrade --apply` JSON → additive `outcome`, `postUpgrade` (`verdict`, `failing[{ruleId,count,sample}]`, `behaviorChanges`), and on each blocked asset `reason` + `nextCommand`. State `absent-local` recreates a recorded gitignored file. | Exit `0` applied and green, `3` applied but red, `2` blocked, `1` error. Scripts comparing against `1` must switch to non-zero. `behaviorChanges` is the shipped per-version table (same sentences as the changelog). JSON fields are additive. `/ark-upgrade` stops when verification is red and does not edit tests, titles, or config in that turn. |
|
|
51
52
|
| **MCP process package honesty (4.5.6; fail-closed in 4.6.4)** | Every MCP tool context → `processPackage` (`processPackageMismatch` / `processStale`, versions, `nextAction`). | Multi-checkout users: restart MCP after pin bump. From 4.6.4, stale process context is non-authoritative; `ark_identity` remains diagnostic and project tools return `PROCESS_PACKAGE_STALE` until restart/retarget. Prefer project-local CLI until identity matched and versions align. |
|
|
52
53
|
| **Doctor design fitness** | `ark-check --doctor --json` → `doctor.designFitness`, `doctor.designSmells[]` | Additive. Stable smell `id`s: `io-under-application`, `handler-in-persistence`, `god-module`, `domain-logic-in-ui`, `facade-sql-in-routes`, `mixed-pattern-cluster`, `soft-contract`. `handler-in-persistence` covers static ES imports/re-exports of framework HTTP surfaces (`next/server`), `defineRoute` calls, and existing handler bodies inside Persistence-role layers or specific persistence paths; `require()` and dynamic `import()` are outside this narrow advisory, and a generic `Infrastructure` role alone is not Persistence. Persistence candidates are filtered and sorted before the bounded content scan so large application prefixes cannot hide the advisory. The detector inspects the first 800 sorted Persistence candidates; later candidates are uninspected, so **absence of a smell is not full-tree proof** above that envelope (incomplete/`partial` analysis also never proves “no smells”). **4.2 feedback hardening:** mode labels preserve the observed SUGGEST/ADAPT/ENFORCE state; a local permission/UI-state `canEdit` name alone is not a domain smell; real UI business rules route Domain → Application → UI; seed/fixture/demo/migration/generated files are not god-module pilots. Each smell has `evidence[]`, `fix`, technical `message`, and plain-language **`outcome`**. Does **not** fail the gate by itself. |
|
|
53
54
|
| **Post-green Shape door** | `doctor.postGreenPath`, `doctor.primaryNextAction`, `doctor.healthyFinishedForbidden` | Additive when `designFitness.designWeak`. Single Shape door (`id: clarify-for-ai`): explore shape-focus → dual-plan B → autopilot only with OK. Never empty plan A = healthy finished. A **passing** `ark-check` human run also prints one dim line naming `--plan`, the smell count and the smell ids. Its weakness test is `isDesignWeak` over the **blocking** violation count — the same input doctor uses, so the two surfaces cannot disagree about `designWeak`, and non-blocking type-only placement debt still gets the line. Report only: never a warning, never an exit-code change, silent when no smell remains, silent on `--changed` (a partial scan would report a slice as the tree) and on `--watch`. A baselined run is not called clean: the opening clause names the suppressed count instead. `--json` is unchanged. |
|
|
54
55
|
| **Golden pattern (new code)** | Optional `.ark/golden-pattern.json`; doctor JSON `doctor.goldenPattern`; MCP `ark_place` / `ark_prepare_write` → `goldenPattern` | Additive, **advisory for NEW code only**. Required fields: `name`, `norm`; optional `newCodeHome`, `examplePath`, `schemaVersion`. **Absent is normal** (no claim). Never ENFORCE; never clears design-weak. Malformed → `invalid: true`, not silent guidance. |
|
|
55
56
|
| **Plan pattern B (Shape bets)** | `ark-check --plan --json` → `plan.patternBets[]`, `plan.goal.designWeak` | Additive. Each bet: `id`, `smellId`, `pilot`, `evidence`, `successSignal`, `killSwitch`, **`neverMechanicalSafe: true`**, `class: "judgment"`. **Never** auto-applied by loop/autoPatch; not a `remediationKind` mechanical-safe. `goal.met` remains edge honesty only. |
|
|
56
|
-
| **Pilot loop (one at a time)** | `plan.pilotLoop` / `doctor.pilotLoop` | Additive.
|
|
57
|
+
| **Pilot loop (one at a time)** | `plan.pilotLoop` / `doctor.pilotLoop` | Additive. Active when at least one pilot candidate exists: a design-weak pattern bet, or a proposed physical-cohesion reshape card. Inactive reason is `no-pilot-candidates`. `oneAtATime`, `neverMechanicalSafe`, **one** `nextPilot` / `extractionCard` (same extraction-card fields: `pilotTarget`, `smellId`, `move`, `successSignal`, `killSwitch`, `doNot[]`). Further candidates stay queued. **One pilot → re-doctor**; never multi-pilot batch; never mechanical-safe. Gate verdict unchanged. |
|
|
57
58
|
| **AI-velocity eval (maintainer)** | Repository-only evidence: `npm run eval:ai-velocity` → `eval/ai-velocity-report.json` | Fixture-measured (no live LLM). Same feature scenario on design-weak vs golden-path arms; metric **`placementTurns`** (agent-equivalent). Golden must be strictly better. Method string lives next to the number. Does not weaken the gate. |
|
|
58
59
|
| **Contract health** | `ark-check --doctor --json` → `doctor.contractHealth`; optional `.ark/contract-smell-acks.json` | Additive, **advisory only** — meta-lint of the contract itself (layer-name heuristics; imprecision costs a warning line, never a verdict); never changes the verdict, `designFitness`, or `patternBets`. Stable smell ids: `contract-bidirectional-allow`, `contract-peripheral-depends-core`, `contract-lateral-adapter-allow`, `contract-dead-rule`; each smell has `severity`, `evidence[]` (sorted, honest `…(+N more)` truncation), `fix`, `message`, plain-language `outcome`, and `acknowledgedEdges` (acks applied to that id). **X03/X06**: the lateral smell does not fire on an adapter reaching its **own family's infra base** — the target reads `<Family><InfraWords…>` (**every** remaining target token an infra word: `Infra(structure)`/`Base`/`Core`/`Shared`/`Common`/`Kernel`/`Platform`/`Foundation`) and the source carries the family token **anywhere** in its name (X06, field: `HoursPersistenceAdapters -> PersistenceInfrastructure` — mid-name families). `PaymentsCoreAdapters` is still a sibling; cross-family edges, non-infra siblings, and the reverse (base → member) still fire. Acknowledgments live in the bounded sidecar (`{ acks: [{ id, edge, reason, reviewBy? }] }`, ≤64 KB / ≤200 entries; bidirectional edges order-insensitive, exact two segments); `contractHealth.acknowledged` counts **applied** acks only (stale acks count 0). **X02 ack lifecycle**: optional `reviewBy` (`YYYY-MM-DD`, strict round-trip validation — `2026-02-30` is malformed) — past the date the ack **stops applying** and the smell returns with `(ack expired …)` annotated evidence; among dated entries a fresh re-ack wins over a dead one, but once ANY dated ack exists for an edge the dated entries govern — a leftover undated duplicate cannot resurrect an expired exception. `detectContractSmells` defaults `today` to the real clock (pass `null` to disable expiry); `analyzeContractSmells` stays pure (clock injected). `contractHealth.ackLifecycle` reports `{ undated, malformed, expiredCount, expired[], staleCount, stale[] (lists capped at 12) }`; undated acks apply (backward compatible) but surface in doctor, report, and the fossilization note even when every smell is suppressed. **X05**: an ack matching **no detected edge** (orphaned by a fixed contract or quieted heuristic, unknown id, or typo'd edge) is `stale` — it suppresses nothing and doctor/report list the exact entries to fix or delete, even at zero visible smells. Malformed `reviewBy` never applies (fail-loud, like a sloppy edge); non-string `reviewBy` → whole file `invalid`. **Absent is normal**; malformed file or edge grammar → ignored + `ackFile.invalid` where applicable, never silent suppression. |
|
|
59
60
|
| **Effect capabilities** | Public root API: `analyzeProject(...).ir.capabilityUses`; the CLI/hook adapters add symbol-aware ambient evidence internally | Additive within IR `1.0`. Seven **closed** ids: `network`, `filesystem`, `clock`, `randomness`, `environment`, `process`, `persistence` (ADR 0009). `collectCapabilityUses` and the Domain vocabulary are internal implementation exports, **not** exports from `arkgate`; the related public low-level helper is `collectForbiddenCapabilityUses`. Direct evidence only — transitive inference never detects. The symbol-aware adapter path covers ambient globals (shadowing/type-only/globalThis-alias precision from the S05/C04 machinery) plus imports; the compiler-free IR engine carries **import-based** uses only (exact module or subpath match, never substring; textual `import type`/`export type` erasure and all-type named lists (`import { type A }`) are type-only there; mixed `{ type A, B }` stays a value import; template-literal bodies are skipped entirely (specifiers inside `${…}` are the symbol path's job); package `require(…)` counts as capability evidence only, while relative `require(…)` also emits a pure-path graph edge). **U04 walls are opt-in:** per-layer `capabilities: { deny: [...] }` or the dual-depth sugar `pure: true` (denies all seven); absence changes no verdict. `CAPABILITY_VIOLATION` is judgment-class (never mechanical-safe) with a port-injection `nextAction`; D7 dedup — evidence already owned by the layer's `forbiddenGlobals` reports only `FORBIDDEN_GLOBAL`. Y08 adds one deliberately narrow import dual: `forbiddenGlobals: ["process"]` owns exact value imports of `process` and `node:process`, but not subpaths or `child_process`; statement-level `import type` / `export type` remains erased on every path (pure-IR residual envelope: mixed `{ type A, B }`, default+named type lists, and comment-interrupted forms stay value imports; symbol path owns full precision). Atomic preflight blocks denied capabilities and that exact dual across a complete multi-file candidate (import-based on the pure path; other ambient evidence adds on the symbol-aware CLI/hook path). T01 policy-delta classifies the surface on **coverage atoms** (`ambient:<entry>` prefix-expanded, narrow `import-exact:<specifier>` duals, and `import:<capability>` for a complete wall): any lost atom is weakening (`fetch`→`XMLHttpRequest`, `Date`→`Date.now`, wall→fg all weaken; finding path `$.layers[name].capabilities`); fg → equivalent-or-stronger wall never needs an acknowledgment; unlowerable custom globals keep raw key comparison. |
|
|
@@ -74,7 +75,7 @@ hardening guide remains repository-hosted rather than duplicated in the gate tar
|
|
|
74
75
|
| **`arkgate/schema/project-identity`** or **`arkgate/schema/ark.project-identity.schema.json`** | MCP canonical project, contract, runtime, expectation, and binding envelope | Schema `1.0`. Initial `expectedRoot` must be the exact project root. A contained descendant can match only when `expectedProjectId` is also present and correct; id-only matching stays non-authoritative. Mismatch codes are `PROJECT_ROOT_MISMATCH`, `PROJECT_ID_MISMATCH`, and `INVALID_PROJECT_EXPECTATION`. |
|
|
75
76
|
| **Package pin dual-truth (4.0)** | doctor JSON `packageVersionTruth`; upgrade JSON/human note when pin behind CLI | Additive, advisory. Surfaces after `upgrade --no-install` when managed CLI is ahead of package.json. |
|
|
76
77
|
| **Managed upgrade self-service honesty (4.5 / DF05)** | `ark upgrade [--json]` → `selfService` (+ human “Self-service honesty” lines) | Additive, advisory. Answers without a maintainer: write-path activation labels per selected host (`hard`\|`advisory`\|`unavailable`) and customized content-identity preserve (`customizedPaths` / `customizedContentPreserved`). Soft hosts never hard; upgrade never invents `hardWriteActive` from disk alone. Always `notAScore: true`. Not a gate input; not part of `planDigest`. |
|
|
77
|
-
| **Product honesty readiness split (4.1.1)** | doctor JSON `productHonesty` | Additive. `unfinished` / `headline` / `primaryNextAction` / `reasonIds` remain; EH adds `contractReadiness` (`ready`\|`partial`\|`not-ready`), `localWriteBoundary` (`advisory`\|`hard`\|`unverified`\|`unknown`), `architectureReasonIds`, `environmentResidualIds` / `environmentResiduals`. Soft-write hosts stay in evidence without alone forcing global **Not finished**. `notAScore: true` always. A physical-cohesion residual that reshape decisions have not suppressed adds `physical-cohesion-residual`, which clears `elegant` and `finished` and sets the headline to residual remaining; the gate verdict, `designFitness`, `designWeak`, and `patternBets` stay unchanged
|
|
78
|
+
| **Product honesty readiness split (4.1.1)** | doctor JSON `productHonesty` | Additive. `unfinished` / `headline` / `primaryNextAction` / `reasonIds` remain; EH adds `contractReadiness` (`ready`\|`partial`\|`not-ready`), `localWriteBoundary` (`advisory`\|`hard`\|`unverified`\|`unknown`), `architectureReasonIds`, `environmentResidualIds` / `environmentResiduals`. Soft-write hosts stay in evidence without alone forcing global **Not finished**. `notAScore: true` always. A physical-cohesion residual that reshape decisions have not suppressed adds `physical-cohesion-residual`, which clears `elegant` and `finished` and sets the headline to residual remaining; the gate verdict, `designFitness`, `designWeak`, and `patternBets` stay unchanged. When that residual still proposes `reshapePilot.nextPilot`, `pilotLoop` is active with that one extraction card. |
|
|
78
79
|
| **Policy transition analysis (3.1.0)** | `analyzePolicyDelta(...)`; MCP `ark_policy_delta`; CLI `--policy-base` / `--policy-base-ref` / `--policy-ack`; check JSON `policyDelta` | Additive schema `1.0`. Classifications and finding ids are deterministic. Weakening/judgment requires an acknowledgement bound to both policy hashes and the exact blocking finding set. A new layer or new allow edge is `judgment-required`. On the CLI/MCP policy-ack plane, `adrPath` must name a short note under `docs/adr/` or `docs/decisions/` (`policyDelta.adrNote`). Domain hash match stays I/O-free. |
|
|
79
80
|
| **Team parliament (law vs feature)** | Optional `stewards` on `ark.config.json` (GitHub handle or email); CLI `--local` / `--changed` / `--against` / `--base` / `--contract-diff` / `--contract-session` / `--persona` / `--author`; check JSON `teamParliament`; `ark status --vs`; write-gate mixed-batch deny | Additive. Law files must not mix with product source. Loosen / baseline-grow are steward-only when `stewards` is set. `--against` ratchets vs the base-ref baseline. `--changed` scans touched sources plus their import closure. `--local` (or `ARK_CHECK_LOCAL=1`) is the same cheap path and stays per `--root`; it cannot combine with `--strict-merge`. Check JSON may add `local`, `scope: "changed"`, `analysisRoot`. `stewards`, `layers[].description`, `layers[].trustBoundary`, and `layers[].owners` are excluded from policy hash. `requireLayerOwners` stays in the hash. Identity is handle or email, not git `user.name`. No org plane. |
|
|
80
81
|
| **Atomic change preflight (3.1.0)** | `preflightChange(...)`; CLI `ark preflight --changes <file> --json`; MCP `ark_prepare_change` | Additive schema `1.0`. One complete governed production-source `{path,content}` / `{path,delete:true}` batch; read-only; returns operation, content/tree/policy/compiler fingerprints and stable graph findings. MCP availability alone is advisory. |
|
package/docs/product-voice.md
CHANGED
|
@@ -66,9 +66,9 @@ Skills never enforce. ξ / Haken stay below the fold.
|
|
|
66
66
|
|
|
67
67
|
## Locked first-contact
|
|
68
68
|
|
|
69
|
-
On the
|
|
70
|
-
`docs/
|
|
71
|
-
`docs/
|
|
69
|
+
On the seven lane openings — `docs/use.md`, `docs/develop.md`, `docs/README.md`,
|
|
70
|
+
`docs/enthusiast/README.md`, `docs/agent-guide.md`, `docs/ai-gates.md`, and
|
|
71
|
+
`docs/package-surface.md` — use:
|
|
72
72
|
|
|
73
73
|
1. **Verbs:** `Write. Check. Ship.`
|
|
74
74
|
2. **Deny:** `When the agent writes a bad import, the write doesn’t land. The same check fails the pull request.`
|
|
@@ -77,6 +77,14 @@ On the eight canonical public openings — `README.md`, `docs/use.md`,
|
|
|
77
77
|
5. **Caption (immediately after the four paragraphs):** `That is **Contener · Guiar · Ordenar**.`
|
|
78
78
|
6. **Technical nouns (below the introduction):** ArkGate is import rules. ArkRules is optional policies. ArkRun is an optional experimental runtime. ArkOrder is the extra for the few big product choices (billing plan, not seat counts) — named when the consumer opts in, never as the first noun. No ξ / Haken / slaving on the first screen.
|
|
79
79
|
|
|
80
|
+
`README.md` is the first-contact module. Its first screen is four beats: what
|
|
81
|
+
(**Contener · Guiar · Ordenar**), why (design the boundary before you implement;
|
|
82
|
+
a green check is **needs a refactor** when leftover mess remains), one command
|
|
83
|
+
(`npx arkgate@4.8.21 start`), and one honest red result (fail-open named; required
|
|
84
|
+
CI is the hard line). The four paragraphs, the not-that line, the host matrix,
|
|
85
|
+
and the release index sit below `## Appendix`. The not-that line does not lead
|
|
86
|
+
the README.
|
|
87
|
+
|
|
80
88
|
Do not lead with folders, `ark.config.json`, “contract”, “gate”, “house”, or “doctor”
|
|
81
89
|
as the first noun. Historical: `If the AI writes an illegal import, the write is rejected`
|
|
82
90
|
and `One architecture config. One check. One coach.` — never first.
|
package/package.json
CHANGED
|
@@ -798,6 +798,14 @@
|
|
|
798
798
|
"uniqueItems": true,
|
|
799
799
|
"minItems": 1
|
|
800
800
|
},
|
|
801
|
+
"sliceIdentity": {
|
|
802
|
+
"type": "string",
|
|
803
|
+
"enum": [
|
|
804
|
+
"path",
|
|
805
|
+
"stars"
|
|
806
|
+
],
|
|
807
|
+
"description": "How a starred sliceFolders prefix is named. Absent and path keep today's ids (every literal and star binding). stars keeps the last literal plus the star bindings, so parallel trees share one feature id. Bare names are unchanged."
|
|
808
|
+
},
|
|
801
809
|
"sharedRoots": {
|
|
802
810
|
"type": "array",
|
|
803
811
|
"items": {
|
package/server.json
CHANGED
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
"url": "https://github.com/pedroknigge/arkgate",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
|
-
"version": "4.8.
|
|
9
|
+
"version": "4.8.21",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "arkgate",
|
|
14
|
-
"version": "4.8.
|
|
14
|
+
"version": "4.8.21",
|
|
15
15
|
"runtimeHint": "npx",
|
|
16
16
|
"transport": {
|
|
17
17
|
"type": "stdio"
|
|
@@ -9,7 +9,7 @@ closed `/ark-*` catalog shipped as flat templates for Ark install.
|
|
|
9
9
|
**Closed catalog** (`ARK_SKILL_NAMES`) — first-class doors plus one-release
|
|
10
10
|
redirect stubs. Add a name only with a live ROADMAP item.
|
|
11
11
|
|
|
12
|
-
Package version when last generated context: **arkgate@4.8.
|
|
12
|
+
Package version when last generated context: **arkgate@4.8.21**
|
|
13
13
|
Schema: agent-skills package contract `1.0`
|
|
14
14
|
|
|
15
15
|
## Skills (closed catalog)
|
|
@@ -366,8 +366,9 @@ Ark protects the **boundary around** a framework, not its internals. Nest/DI pub
|
|
|
366
366
|
`sliceFolders`: a bare name stays an unanchored one-segment match (`features` on
|
|
367
367
|
`src/lib/features/projects/rfi/x.ts` is `features/projects`); a filename is never the
|
|
368
368
|
child segment. A starred prefix (`lib/features/*/*`) is anchored like `sharedRoots`
|
|
369
|
-
(offset 0 or 1)
|
|
370
|
-
(`lib/features/projects/rfi`)
|
|
369
|
+
(offset 0 or 1). The slice id includes the literal prefix plus the directories
|
|
370
|
+
the stars bind (`lib/features/projects/rfi`), so parallel trees get different ids
|
|
371
|
+
(tracked in #308). Before trusting green, add one deliberate
|
|
371
372
|
feature-to-feature import and expect `cross-slice`.
|
|
372
373
|
If one edge dominates residual debt: **STOP — do not continue this skill as complete.** **STOP — concentrated edge:** rewrite `ark.config.json` **in this turn** with source evidence (do not freeze a wrong config or grind N freezes).
|
|
373
374
|
Empty Domain/Persistence + I/O under Application → false-green.
|
|
@@ -437,5 +438,7 @@ End with **exactly** these headings (markdown `###`):
|
|
|
437
438
|
- **Handoff:** `/ark-…` / CLI / `none`
|
|
438
439
|
- **Incomplete?** `no` | `yes — <what is missing>`
|
|
439
440
|
|
|
441
|
+
When `doctor.productHonesty.finished` is `false`, **Incomplete? no** is disallowed. Write `yes — <pilotLoop.extractionCard.move or residual>`.
|
|
442
|
+
|
|
440
443
|
If a **STOP** handoff applies and you continued as if done, set **Incomplete?** to `yes`.
|
|
441
444
|
**Skill incomplete if missing** any of the bullets above.
|
|
@@ -59,3 +59,5 @@ Skill incomplete if missing any field below.
|
|
|
59
59
|
- **Compass:** top residual lenses | `n/a`
|
|
60
60
|
- **Handoff:** `/ark-adopt` / `/ark-place` / `none`
|
|
61
61
|
- **Incomplete?** `no` | `yes — <what is missing>`
|
|
62
|
+
|
|
63
|
+
When `doctor.productHonesty.finished` is `false`, **Incomplete? no** is disallowed. Write `yes — <pilotLoop.extractionCard.move or residual>`.
|
|
@@ -110,10 +110,10 @@ decision-grade explore pass **and** without opening violating files.
|
|
|
110
110
|
layout — no pilot”; never reconstruct that dead card from `findings`. When the user accepts,
|
|
111
111
|
defers, or rejects a live card, persist its exact `decisionTarget` with a non-empty reason and
|
|
112
112
|
optional `reviewBy` in `.ark/reshape-decisions.json`; never infer a verdict from golden prose.
|
|
113
|
-
A cohesion residual starts one reshape judgment card
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
113
|
+
A cohesion residual starts **one** reshape judgment card on `pilotLoop.nextPilot`
|
|
114
|
+
(one pilot, then re-doctor). The loop is active when a pilot candidate exists,
|
|
115
|
+
including that reshape card when the tree is not design-weak. It does not start
|
|
116
|
+
a pattern-bet batch.
|
|
117
117
|
|
|
118
118
|
## MCP workspace binding (mandatory)
|
|
119
119
|
|
|
@@ -308,5 +308,7 @@ End with **exactly** these headings (markdown `###`):
|
|
|
308
308
|
- **Handoff:** `/ark-…` / CLI / `none`
|
|
309
309
|
- **Incomplete?** `no` | `yes — <what is missing>`
|
|
310
310
|
|
|
311
|
+
When `doctor.productHonesty.finished` is `false`, **Incomplete? no** is disallowed. Write `yes — <pilotLoop.extractionCard.move or residual>`.
|
|
312
|
+
|
|
311
313
|
If a **STOP** handoff applies and you continued as if done, set **Incomplete?** to `yes`.
|
|
312
314
|
**Skill incomplete if missing** any of the bullets above.
|
|
@@ -64,3 +64,5 @@ Skill incomplete if missing any field below.
|
|
|
64
64
|
- **Compass:** top residual lenses | `n/a`
|
|
65
65
|
- **Handoff:** `/ark-adopt` / `/ark-autopilot` / `/ark-order` / `none`
|
|
66
66
|
- **Incomplete?** `no` | `yes — <what is missing>`
|
|
67
|
+
|
|
68
|
+
When `doctor.productHonesty.finished` is `false`, **Incomplete? no** is disallowed. Write `yes — <pilotLoop.extractionCard.move or residual>`.
|
|
@@ -200,5 +200,7 @@ End with **exactly** these headings (markdown `###`):
|
|
|
200
200
|
- **Handoff:** `/ark-…` / CLI / `none`
|
|
201
201
|
- **Incomplete?** `no` | `yes — <what is missing>`
|
|
202
202
|
|
|
203
|
+
When `doctor.productHonesty.finished` is `false`, **Incomplete? no** is disallowed. Write `yes — <pilotLoop.extractionCard.move or residual>`.
|
|
204
|
+
|
|
203
205
|
If a **STOP** handoff applies and you continued as if done, set **Incomplete?** to `yes`.
|
|
204
206
|
**Skill incomplete if missing** any of the bullets above.
|
|
@@ -244,6 +244,8 @@ End with **exactly** these headings (markdown `###`):
|
|
|
244
244
|
- **Handoff:** `/ark-…` / CLI / `none`
|
|
245
245
|
- **Incomplete?** `no` | `yes — <what is missing>`
|
|
246
246
|
|
|
247
|
+
When `doctor.productHonesty.finished` is `false`, **Incomplete? no** is disallowed. Write `yes — <pilotLoop.extractionCard.move or residual>`.
|
|
248
|
+
|
|
247
249
|
Prefer **Incomplete?** `yes` if the showcase report was generated but the browser-open step was
|
|
248
250
|
skipped without CI/headless/user-opt-out reason.
|
|
249
251
|
|
|
@@ -355,8 +355,8 @@ stays in the same layer and the same slice id. If no governed destination keeps
|
|
|
355
355
|
`nextPilot` is null — do not invent a folder outside the contract. Success is a smaller
|
|
356
356
|
cluster with the layer and slice id unchanged and the card still proposed; a green gate is
|
|
357
357
|
not success. A cohesion residual (`physical-cohesion-residual`) starts that one reshape
|
|
358
|
-
judgment card. It does not start the pattern-bet apply
|
|
359
|
-
|
|
358
|
+
judgment card as `pilotLoop.nextPilot`. It does not start the pattern-bet apply
|
|
359
|
+
loop. Apply that one card, then re-doctor.
|
|
360
360
|
|
|
361
361
|
### C. Coupling & debt (measure, don’t guess)
|
|
362
362
|
Prefer evidence over aesthetics:
|
|
@@ -534,5 +534,7 @@ End with **exactly** these headings (markdown `###`):
|
|
|
534
534
|
- **Handoff:** `/ark-…` / CLI / `none`
|
|
535
535
|
- **Incomplete?** `no` | `yes — <what is missing>`
|
|
536
536
|
|
|
537
|
+
When `doctor.productHonesty.finished` is `false`, **Incomplete? no** is disallowed. Write `yes — <pilotLoop.extractionCard.move or residual>`.
|
|
538
|
+
|
|
537
539
|
If a **STOP** handoff applies and you continued as if done, set **Incomplete?** to `yes`.
|
|
538
540
|
**Skill incomplete if missing** any of the bullets above.
|
|
@@ -82,3 +82,5 @@ Skill incomplete if missing any field below.
|
|
|
82
82
|
- **Compass:** top residual lenses | `n/a`
|
|
83
83
|
- **Handoff:** `/ark-autopilot` / `/ark-adopt` / `none`
|
|
84
84
|
- **Incomplete?** `no` | `yes — <what is missing>`
|
|
85
|
+
|
|
86
|
+
When `doctor.productHonesty.finished` is `false`, **Incomplete? no** is disallowed. Write `yes — <pilotLoop.extractionCard.move or residual>`.
|
|
@@ -77,3 +77,5 @@ Skill incomplete if missing any field below.
|
|
|
77
77
|
- **Compass:** top residual lenses | `n/a`
|
|
78
78
|
- **Handoff:** `/ark-autopilot` / `/ark-explore` / `none`
|
|
79
79
|
- **Incomplete?** `no` | `yes — <what is missing>`
|
|
80
|
+
|
|
81
|
+
When `doctor.productHonesty.finished` is `false`, **Incomplete? no** is disallowed. Write `yes — <pilotLoop.extractionCard.move or residual>`.
|
|
@@ -196,5 +196,7 @@ End with **exactly** these headings (markdown `###`):
|
|
|
196
196
|
- **Handoff:** `/ark-…` / CLI / `none`
|
|
197
197
|
- **Incomplete?** `no` | `yes — <what is missing>`
|
|
198
198
|
|
|
199
|
+
When `doctor.productHonesty.finished` is `false`, **Incomplete? no** is disallowed. Write `yes — <pilotLoop.extractionCard.move or residual>`.
|
|
200
|
+
|
|
199
201
|
If a **STOP** handoff applies and you continued as if done, set **Incomplete?** to `yes`.
|
|
200
202
|
**Skill incomplete if missing** any of the bullets above.
|
|
@@ -317,5 +317,7 @@ End with **exactly** these headings (markdown `###`):
|
|
|
317
317
|
- **Handoff:** `/ark-…` / CLI / `none`
|
|
318
318
|
- **Incomplete?** `no` | `yes — <what is missing>`
|
|
319
319
|
|
|
320
|
+
When `doctor.productHonesty.finished` is `false`, **Incomplete? no** is disallowed. Write `yes — <pilotLoop.extractionCard.move or residual>`.
|
|
321
|
+
|
|
320
322
|
If a **STOP** handoff applies and you continued as if done, set **Incomplete?** to `yes`.
|
|
321
323
|
**Skill incomplete if missing** any of the bullets above.
|
|
@@ -180,5 +180,7 @@ End with **exactly** these headings (markdown `###`):
|
|
|
180
180
|
- **Handoff:** `/ark-…` / CLI / `none`
|
|
181
181
|
- **Incomplete?** `no` | `yes — <what is missing>`
|
|
182
182
|
|
|
183
|
+
When `doctor.productHonesty.finished` is `false`, **Incomplete? no** is disallowed. Write `yes — <pilotLoop.extractionCard.move or residual>`.
|
|
184
|
+
|
|
183
185
|
If a **STOP** handoff applies and you continued as if done, set **Incomplete?** to `yes`.
|
|
184
186
|
**Skill incomplete if missing** any of the bullets above.
|
|
@@ -66,3 +66,5 @@ Skill incomplete if missing any field below.
|
|
|
66
66
|
- **Compass:** top residual lenses | `n/a`
|
|
67
67
|
- **Handoff:** `/ark-explore` / `/ark-autopilot` / `none`
|
|
68
68
|
- **Incomplete?** `no` | `yes — <what is missing>`
|
|
69
|
+
|
|
70
|
+
When `doctor.productHonesty.finished` is `false`, **Incomplete? no** is disallowed. Write `yes — <pilotLoop.extractionCard.move or residual>`.
|
|
@@ -40,6 +40,8 @@ Invoking this skill **is** the approval. Preview, then `--apply` **in this turn*
|
|
|
40
40
|
Stopping at preview is incomplete unless the probe failed or a conflict needs
|
|
41
41
|
`--accept-conflicts` / `--refresh-skills` consent.
|
|
42
42
|
|
|
43
|
+
If post-upgrade verification is red: **STOP**. Do not edit tests, titles, or config in the upgrade turn. Report `failing[]` and `behaviorChanges[]` and hand off. Incomplete? yes.
|
|
44
|
+
|
|
43
45
|
For session 0, start with `/ark-adopt` (or `ark-check --recommend`); brownfield
|
|
44
46
|
honesty is `/ark-adopt` before this upgrade flow.
|
|
45
47
|
|
|
@@ -171,7 +173,11 @@ ArkGate has **always-on Layers** plus opt-in extras. The user chooses extras; yo
|
|
|
171
173
|
`--plan-digest <sha256:…>` and applies only that exact candidate. A changed file
|
|
172
174
|
or selection invalidates the digest instead of being overwritten.
|
|
173
175
|
- Missing or conflicted assets previously recorded as managed require explicit
|
|
174
|
-
`--accept-conflicts
|
|
176
|
+
`--accept-conflicts`, unless the missing file is gitignored (`absent-local`,
|
|
177
|
+
for example a per-machine `.mcp.json` in a fresh worktree). That file is
|
|
178
|
+
recreated without consent. Stop and obtain user consent before using
|
|
179
|
+
`--accept-conflicts` on a real deletion or conflict. Every blocked asset
|
|
180
|
+
carries `reason` and `nextCommand`.
|
|
175
181
|
- Customized files are preserved. Unrelated source files and similar filenames
|
|
176
182
|
are never adopted. The command never writes a Codex home or another global
|
|
177
183
|
directory implicitly.
|
|
@@ -184,7 +190,8 @@ ArkGate has **always-on Layers** plus opt-in extras. The user chooses extras; yo
|
|
|
184
190
|
|---|---|---|
|
|
185
191
|
| `current` | Content identity matches the candidate. | Record/adopt safely; metadata-only stamps may refresh. |
|
|
186
192
|
| `stale` | Recorded managed content still matches its old identity. | Safe candidate replacement. |
|
|
187
|
-
| `missing` | Candidate is absent. | Create if new; require consent if a recorded asset was deleted. |
|
|
193
|
+
| `missing` | Candidate is absent and is not a gitignored local file. | Create if new; require consent if a recorded asset was deleted. Read `reason` and `nextCommand`. |
|
|
194
|
+
| `absent-local` | Recorded file is missing and gitignored (per-machine file in a fresh worktree). | Recreate it. No consent. |
|
|
188
195
|
| `customized` | User content diverged without a competing managed base. | Preserve it. Opt-in rewrite for **skills only**: `--refresh-skills`. |
|
|
189
196
|
| `conflicted` | Both managed base and user content diverged. | Preserve and require explicit consent (`--accept-conflicts`). |
|
|
190
197
|
| `retired` | A recorded asset is no longer selected by the candidate. | Preserve its file and manifest identity; take no action. |
|
|
@@ -285,16 +292,19 @@ ArkGate has **always-on Layers** plus opt-in extras. The user chooses extras; yo
|
|
|
285
292
|
(unless more deliberate refreshes remain).
|
|
286
293
|
|
|
287
294
|
5. **Verify enforcement and architecture (post-upgrade checks).** Read apply JSON
|
|
288
|
-
`postUpgradeChecks` when present.
|
|
295
|
+
`postUpgrade` (`verdict`, `failing`, `behaviorChanges`) and `postUpgradeChecks` when present.
|
|
296
|
+
Exit 3 means the files were applied and the architecture check is red. Also run:
|
|
289
297
|
`npx arkgate-check --doctor --json` (or the project-local `ark-check`) and
|
|
290
298
|
the same fail-closed architecture command used by managed apply (normally
|
|
291
299
|
`npx arkgate-check --root . --config ark.config.json --strict-merge --json`).
|
|
292
|
-
Require `completeness: "complete"` and `ok: true
|
|
300
|
+
Require `completeness: "complete"` and `ok: true` before calling the upgrade done.
|
|
301
|
+
If post-upgrade verification is red: **STOP**. Do not edit tests, titles, or config in the upgrade turn. Report `failing[]` and `behaviorChanges[]` and hand off. Incomplete? yes.
|
|
302
|
+
Handoff is `/ark-autopilot` after the report; do not regenerate a baseline without
|
|
303
|
+
explicit approval. Confirm `doctor.improvementCompass` and
|
|
293
304
|
`doctor.deepModuleCoach` honesty. Run `npx arkgate agents-md --check` and
|
|
294
305
|
`npx arkgate status --json`. If MCP was used, restart MCP after package bump and re-bind
|
|
295
306
|
identity. Treat provider-unavailable CI required-check evidence as `unverified`, never as proof
|
|
296
|
-
that merges are blocked.
|
|
297
|
-
explicit approval.
|
|
307
|
+
that merges are blocked.
|
|
298
308
|
|
|
299
309
|
## Active host vs deferred hosts
|
|
300
310
|
|
|
@@ -332,5 +342,8 @@ End with exactly this structure:
|
|
|
332
342
|
- **Handoff:** `/ark-…`, CLI action, or `none`
|
|
333
343
|
- **Incomplete?** `no` or `yes — <missing work>`
|
|
334
344
|
|
|
345
|
+
When `doctor.productHonesty.finished` is `false`, **Incomplete? no** is disallowed. Write `yes — <pilotLoop.extractionCard.move or residual>`.
|
|
346
|
+
|
|
335
347
|
If a required verification did not run or a conflict remains blocked, report the
|
|
336
|
-
task incomplete.
|
|
348
|
+
task incomplete. If post-upgrade verification is red: **STOP**. Do not edit tests, titles, or config in the upgrade turn. Report `failing[]` and `behaviorChanges[]` and hand off. Incomplete? yes.
|
|
349
|
+
Deferred hosts (including Codex when inactive) never make Incomplete? yes.
|