arkgate 4.8.22 → 4.8.23

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.
Files changed (41) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +2 -2
  3. package/bin/ark-check-runtime.mjs +4 -2
  4. package/bin/ark-layer-match.mjs +606 -11
  5. package/bin/lib/analysis-engine.mjs +11 -11
  6. package/bin/lib/config-contract.mjs +492 -1
  7. package/bin/lib/diagnostic-catalog.mjs +32 -0
  8. package/bin/lib/doctor-advisories.mjs +60 -1
  9. package/bin/lib/doctor-plan.mjs +2 -2
  10. package/bin/lib/enforcement-honesty.mjs +22 -0
  11. package/bin/lib/flat-parent-pilot.mjs +252 -0
  12. package/bin/lib/html-report-advisories.mjs +2 -0
  13. package/bin/lib/html-report-depth.mjs +3 -1
  14. package/bin/lib/physical-cohesion.mjs +16 -18
  15. package/bin/lib/pilot-loop.mjs +21 -8
  16. package/bin/lib/team-parliament-io.mjs +4 -2
  17. package/dist/{configTypes-CTELo87-.d.ts → configTypes-Bbf_MFGe.d.ts} +36 -2
  18. package/dist/{diagnosticCatalog-WD2TPSwZ.d.ts → diagnosticCatalog-35mrwAHe.d.ts} +13 -3
  19. package/dist/eslint/index.cjs +4 -4
  20. package/dist/eslint/index.d.ts +51 -5
  21. package/dist/eslint/index.js +4 -4
  22. package/dist/index.cjs +35 -35
  23. package/dist/index.d.ts +104 -5
  24. package/dist/index.js +35 -35
  25. package/dist/nestjs/index.cjs +9 -9
  26. package/dist/nestjs/index.d.ts +3 -3
  27. package/dist/nestjs/index.js +9 -9
  28. package/dist/runtime/index.cjs +13 -13
  29. package/dist/runtime/index.d.ts +6 -6
  30. package/dist/runtime/index.js +13 -13
  31. package/dist/{types-yDNEQ603.d.ts → types-Bdj32QwA.d.ts} +1 -1
  32. package/dist/{types-fQ9-KrBj.d.ts → types-Ik_OakcI.d.ts} +1 -1
  33. package/docs/README.md +2 -1
  34. package/docs/agent-guide.md +9 -1
  35. package/docs/configuration.md +92 -1
  36. package/docs/diagnostics.md +32 -0
  37. package/docs/product-voice.md +1 -1
  38. package/package.json +1 -1
  39. package/schemas/ark.config.schema.json +124 -2
  40. package/server.json +2 -2
  41. package/templates/agent-skills/README.md +1 -1
@@ -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-fQ9-KrBj.js';
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-Ik_OakcI.js';
2
2
 
3
3
  /**
4
4
  * PolicyEngine
@@ -1,4 +1,4 @@
1
- import { a as ArkConfigRule, f as ArkConfigLayer, A as ArkConfig } from './configTypes-CTELo87-.js';
1
+ import { a as ArkConfigRule, f as ArkConfigLayer, A as ArkConfig } from './configTypes-Bbf_MFGe.js';
2
2
 
3
3
  /**
4
4
  * Policy types for the Ark kernel.
package/docs/README.md CHANGED
@@ -73,7 +73,8 @@ 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 release: [CHANGELOG](../CHANGELOG.md) (`arkgate@4.8.22`; confirm npm with `npm view arkgate@4.8.22 version`; does not close `K01`).
76
+ Current release: [CHANGELOG](../CHANGELOG.md) (`arkgate@4.8.23`; confirm npm with `npm view arkgate@4.8.23 version`; does not close `K01`).
77
+ Prior published: [CHANGELOG](../CHANGELOG.md) (`arkgate@4.8.22`).
77
78
  Prior published: [CHANGELOG](../CHANGELOG.md) (`arkgate@4.8.21`).
78
79
  Prior published: [CHANGELOG](../CHANGELOG.md) (`arkgate@4.8.20`). Plain-English history: [arkgate.online/changelog](https://www.arkgate.online/changelog/).
79
80
  Prior published: [releases/4.8.11.md](releases/4.8.11.md) (`arkgate@4.8.11`).
@@ -438,7 +438,14 @@ clusters per anchor directory (concentration, not volume — dispersed hooks nev
438
438
  fixed corpus-calibrated thresholds; anchors under `app/`/`pages/` are `fixedByConvention` and
439
439
  never move. `reshapePilot.nextPilot` is a **proposed** one-at-a-time card (`moveSample`,
440
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
441
+ `pilotLoop` extraction card if no design-weak pattern bet is ahead of it. A flat file
442
+ at universe level that exactly one child slice imports is a later candidate
443
+ (`doctor.flatParentPilot`, source `flat-parent`): the file, that child, and a
444
+ destination folder inside the child that keeps the file's layer. Two importers,
445
+ or none, produce no card. The sentence is a suggestion with that importer as
446
+ its evidence. It does not change ark-check. `destinationKeepsLayerAndSlice`
447
+ uses the same slice identity as the walls, so `sliceIdentity: "stars"` cannot
448
+ treat two children as one slice. Run a card only via
442
449
  `/ark-loop` through the write gate + atomic preflight; merges are `/ark-adopt` /
443
450
  `/ark-autopilot` judgment cards. `notAScore`, never a verdict/`designFitness` input; there
444
451
  is no apply path.
@@ -1145,6 +1152,7 @@ edges are not denied by that rule.
1145
1152
  - **`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
1153
  - **`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.
1147
1154
  - **Fail-closed:** missing paths, empty/unresolvable slice folders, or unclassifiable either side → **deny** via peerIsolation (cannot prove same-slice).
1155
+ - **`childSlices`** (optional): a second wall under the same rule. The universe wall runs first and is unchanged when the block is absent. With it present, a cross-universe deny is `reasonId` `CROSS_PARENT_SLICE` (never advisory). Inside one universe, `commonFolders` and flat files are common; a child may import them; common may import a child only when `parentMayImportChild` is true. Sibling crossings are `CROSS_SIBLING_SLICE` — error when `siblings` is `deny` (the default), warning when `advisory`, and a new one past the baseline still fails. `ruleId` stays `LAYER_IMPORT_VIOLATION`. arkgate 4.8.22 and older reject the key.
1148
1156
  - **`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.
1149
1157
  - **`allowedCrossSlice`** (4.8.4): `[{ "from": "features/checkout", "to": "features/catalog" }]` — one directed slice→slice edge the repo declares on purpose. The reverse still denies.
1150
1158
  - **The denial names its reason:** `cross-slice edge a → b` (a fact about the code) vs `unclassifiable path (…)`, `no slice folders`, `no path evidence` (facts about the evidence ArkGate had).
@@ -251,7 +251,7 @@ process module-capability family must be denied.
251
251
  Rule fields:
252
252
 
253
253
  - `from`, `to`, `allowed`, `message`, `peerIsolation`, `sliceFolders`, `sliceIdentity`,
254
- `sharedRoots`, `allowedCrossSlice`, `sharedImportsSlice`
254
+ `sharedRoots`, `allowedCrossSlice`, `sharedImportsSlice`, `childSlices`
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
@@ -276,6 +276,90 @@ Rule fields:
276
276
  same id, and the warning names both paths (`admin/features/*` and `public/features/*`
277
277
  both bind as `features/*`). That warning is advisory. Unrelated trees that share a
278
278
  last folder name should stay on `path`.
279
+ - `childSlices` is an optional inner wall on a `peerIsolation` rule. Absent means today's
280
+ universe wall, byte for byte: no `reasonId`, same messages, same doctor output.
281
+ `sliceFolders` names the children (`lib/features/*/*` under a universe id `features/projects`).
282
+ `sliceIdentity` is the same `path` | `stars` choice. `commonFolders` (directory names such as
283
+ `domain`) and a flat file whose child id does not grow past the universe id are universe
284
+ common. A child may import that common code. Common code may import a child only when
285
+ `parentMayImportChild` is true (default false). `siblings` is `deny` (default, also when the
286
+ key is omitted), `advisory`, or `{ "default": "deny" | "advisory", "enforce": [...] }`.
287
+ The universe wall runs first. A denied cross-universe edge is
288
+ `reasonId` `CROSS_PARENT_SLICE` and is never advisory. A denied sibling edge is
289
+ `CROSS_SIBLING_SLICE`: an error when `siblings` is `deny` or `{ "default": "deny" }`,
290
+ a warning (`failsStrict: false`) when `advisory`. With `{ "default": "advisory", "enforce" }`,
291
+ a crossing whose importer is listed is an error. Every other sibling crossing stays a warning.
292
+ `enforce` entries are child slice ids (`features/projects/rfi`) or subtree paths
293
+ (`lib/features/projects/rfi` or `src/lib/features/projects/rfi`). A child id matches that
294
+ importer's child id. A path matches when the importer file sits in that directory.
295
+ Bare names do not match. `*` is not a wildcard on this list. `default: "deny"` denies every
296
+ sibling crossing; the list cannot loosen it. A new advisory crossing past the recorded
297
+ baseline still fails, the same ratchet as a string `advisory`. An enforce list does not
298
+ change that function. The baseline key stays `ruleId|file|fromLayer|toLayer|target` and does
299
+ not include `reasonId`. `productHonesty.finished` stays false while any child wall is
300
+ advisory, including `{ "default": "advisory", "enforce": [...] }`. The list does not finish
301
+ the house. Doctor `slices` is `{ crossParent, crossSibling, pairs }` for the directed universe
302
+ pairs that occur. A child id that does not extend its universe id warns
303
+ `CONFIG_CHILD_SLICE_EXTENDS` and is treated as universe common. arkgate 4.8.22 and older
304
+ reject `childSlices` (`CONFIG_CHILD_SLICES_VERSION`). A build that still types `siblings` as
305
+ the string enum `deny | advisory` rejects the object at config load
306
+ (`must be one of deny, advisory` at `$.rules[n].childSlices.siblings`). It does not ignore
307
+ the object. No published release through 4.8.22 accepts `{ default, enforce }`. Ship that
308
+ form only on a release that includes it.
309
+ `childSlices.allowedCrossSlice` is a directed list on the child block only:
310
+ `{ "from": "features/projects/*", "to": "features/projects/d2d-item" }`.
311
+ `*` matches one whole path segment. `**` and a partial segment (`feat*`) are
312
+ rejected at config load. A bare name (no `/`) is rejected, because it is
313
+ ambiguous across universes. The list clears only a `CROSS_SIBLING_SLICE`,
314
+ and only after the universe wall has allowed the edge. It never clears
315
+ `CROSS_PARENT_SLICE` or `CROSS_PARENT_VIA_SHARED`. A pattern that can name
316
+ two universes (`features/*/*` to `features/management/eos`) leaves the
317
+ cross-parent finding in place and warns `CONFIG_CHILD_SLICE_CROSS_UNIVERSE`
318
+ (`failsStrict: false`). The universe `allowedCrossSlice` does not read this
319
+ list and still treats `*` as a literal slice id, byte for byte with 4.8.22.
320
+ Adding an entry is a weakening policy delta. Removing one is strengthening.
321
+ Additions and removals together need a judgment. A wildcard that widens a
322
+ literal entry is weakening and needs the same acknowledgement. A build that
323
+ accepts `childSlices` and still rejects unknown fields fails at config load
324
+ (`unknown field` at `$.rules[n].childSlices.allowedCrossSlice`). It does not
325
+ ignore the key. No published release through 4.8.22 accepts the wildcard.
326
+ Ship it only on a release that includes this field.
327
+ `childSlices.sliceAliases` maps files that sit outside every slice folder onto
328
+ a child that already exists: `{ "from": "lib/compliance/**", "to": "features/projects/compliance" }`.
329
+ `to` is the universe id the universe wall already knows, plus one child segment.
330
+ A bare name, that universe id alone, an unknown universe, and a wildcard in `to`
331
+ are rejected at config load (`child of an existing universe`). The source glob
332
+ may cover only files the slice folders do not already classify. Overlap with a
333
+ universe `sliceFolders` entry or a child `sliceFolders` entry is rejected
334
+ (`overlaps a slice folder`). Two aliases that can match one file are rejected
335
+ (`two slice aliases match the same file`). An aliased file takes the target
336
+ universe id and the target child id for both walls, so an import into another
337
+ universe is `CROSS_PARENT_SLICE` and an import into another child of the same
338
+ universe is `CROSS_SIBLING_SLICE`. Same-child imports and imports into that
339
+ universe's common folders follow the existing child wall. Doctor lists every
340
+ alias as an owed move: the source glob, the target slice, the destination
341
+ folder, and the files. The section says the files are not finished. Aliases
342
+ are debt. `productHonesty.finished` stays false while any alias is set.
343
+ Adding aliases is a strengthening policy delta (unclassified files come under
344
+ the walls). Removing them is weakening (those files leave the walls) and needs
345
+ the same hash-bound acknowledgement as any other weakening. Additions and
346
+ removals in one change, including a retarget, are judgment-required. A folder
347
+ edit already asks for a judgment and covers the alias list. The baseline key
348
+ stays `ruleId|file|fromLayer|toLayer|target` and does not include `reasonId`.
349
+ The write hook, ESLint, snippet analysis, ark-check, and CI all see the alias
350
+ through one resolver. There is no skip flag. arkgate 4.8.22 and older reject
351
+ `childSlices`. A build that accepts `childSlices` and still rejects unknown
352
+ fields fails at config load (`unknown field` at `$.rules[n].childSlices.sliceAliases`).
353
+ It does not ignore the key. No published release through 4.8.22 accepts
354
+ `sliceAliases`. Ship a config that sets it only on a release that includes
355
+ this field. The write hook, ESLint, snippet analysis, ark-check, and CI all
356
+ see the per-edge decision.
357
+
358
+ Doctor may suggest moving a flat file that sits at universe level when
359
+ exactly one child slice imports it. The card names the file, that child, and
360
+ a destination folder inside the child that keeps the file's layer. It is a
361
+ suggestion. It is not a config field, not a finding, and not an ark-check
362
+ result. A file two children import stays where it is.
279
363
 
280
364
  ```jsonc
281
365
  {
@@ -346,6 +430,13 @@ is evidence:
346
430
  to `"deny"`. That hop is direct only — `allowedCrossSlice` does not excuse it. A green
347
431
  `ark-check` prints one line per layer edge (the count and three examples) and says the
348
432
  wall is direct-only. Every edge stays in `ark-check --json` and `ark-check --doctor`.
433
+ `"deny-cross-parent"` does not change that direct hop: it stays a `SHARED_IMPORTS_SLICE`
434
+ warning. It adds a whole-graph finding when a slice reaches a **different** universe
435
+ only through a shared root (`reasonId` `CROSS_PARENT_VIA_SHARED` on
436
+ `LAYER_IMPORT_VIOLATION`). A shared hop that stays inside one universe is not a finding.
437
+ That pass runs in `ark-check` and CI. The write hook and ESLint see one edge at a time
438
+ and do not block it. arkgate 4.8.22 and older reject the value at config load (`must be
439
+ one of deny`). They do not ignore it and they do not treat it as `"deny"`.
349
440
  - `allowedCrossSlice` entries match a full slice id (`features/catalog`) or a bare slice name
350
441
  (`catalog`), and only in the direction written. The reverse edge still denies. A bare name
351
442
  matches that name under **any** slice folder, so in a repo with several slice parents
@@ -102,6 +102,9 @@ Link form for agents: `docs/diagnostics.md#RULE_ID` (exact-case HTML anchors bel
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
104
  | [`CONFIG_SLICE_IDENTITY_COLLISION`](#CONFIG_SLICE_IDENTITY_COLLISION) | config | Starred slice prefixes share one id |
105
+ | [`CONFIG_CHILD_SLICES_VERSION`](#CONFIG_CHILD_SLICES_VERSION) | config | childSlices needs a newer arkgate |
106
+ | [`CONFIG_CHILD_SLICE_EXTENDS`](#CONFIG_CHILD_SLICE_EXTENDS) | config | Child slice id does not extend its universe |
107
+ | [`CONFIG_CHILD_SLICE_CROSS_UNIVERSE`](#CONFIG_CHILD_SLICE_CROSS_UNIVERSE) | config | Child slice allowance cannot cross the universe wall |
105
108
  | [`ARK_UNKNOWN`](#ARK_UNKNOWN) | meta | Unknown diagnostic |
106
109
 
107
110
  ## Layer and dependency graph
@@ -114,6 +117,8 @@ Link form for agents: `docs/diagnostics.md#RULE_ID` (exact-case HTML anchors bel
114
117
 
115
118
  - **Why:** This file imported a folder it may not reach. The write doesn’t land. The same check fails the pull request.
116
119
  - **Fix:** Branch by import kind: constants/types/pure → adopt into DomainModel or SharedKernel (do not invent a port); kernel/events/bootstrap from Persistence → inject a port or move the map to SharedTypes (Persistence must not emit); define a port only when the target is a real use-case. Type-only edges use `import type`. Then preflight again. Do not weaken the layer rule without a hash-bound policy acknowledgement.
120
+ - **Slice reasons:** the ruleId stays `LAYER_IMPORT_VIOLATION`. When a rule sets `childSlices`, the finding may also carry `reasonId` `CROSS_PARENT_SLICE` (this import crosses two universe slices; the child wall cannot allow another universe) or `CROSS_SIBLING_SLICE` (this import crosses two feature slices inside one universe). `siblings` may be `"deny"`, `"advisory"`, or `{ "default", "enforce" }`. An enforced importer (`enforce` entry is that child id or a subtree path of the file) is an error. Every other sibling crossing is a warning, and a new one past the baseline still fails. `default: "deny"` denies every sibling crossing. `childSlices.allowedCrossSlice` may use a whole-segment `*` and clears only a sibling crossing. It does not clear `CROSS_PARENT_SLICE` or `CROSS_PARENT_VIA_SHARED`. The universe `allowedCrossSlice` still treats `*` as a literal. `childSlices.sliceAliases` maps a source path glob onto a child slice id (the universe id plus one child segment). An aliased file takes that universe id and that child id for both walls, so an import into another universe is still `CROSS_PARENT_SLICE`. A bare name, a universe id alone, an unknown universe, and a wildcard in `to` are rejected at config load. A glob that overlaps a slice folder is rejected. Two aliases that can match the same file are rejected. Doctor lists each alias as an owed move — the files, the target slice, and the destination folder — and does not count those files as finished. Adding aliases is a strengthening policy delta. Removing them is weakening. Additions and removals together, including a retarget, need a judgment. The baseline key does not include `reasonId`. Without `childSlices`, `reasonId` is absent on a direct edge. The write hook, ESLint, snippet analysis, ark-check, and CI all see this per-edge decision. arkgate 4.8.22 and older reject `childSlices`. A build that still types `siblings` as a string enum rejects the object at config load (`must be one of deny, advisory`). A build that still rejects unknown `childSlices` fields rejects `allowedCrossSlice` and `sliceAliases` at config load (`unknown field`). No published release through 4.8.22 accepts `sliceAliases`. Doctor may also suggest moving a flat universe-level file that exactly one child imports (`doctor.flatParentPilot`). That suggestion is not a finding, not a `ruleId`, and not part of the baseline key. A file imported by two children, or by none, is not suggested.
121
+ - **`CROSS_PARENT_VIA_SHARED`:** `sharedImportsSlice` is `"deny-cross-parent"`. A slice reaches another universe only through a shared root. The finding's `file` is the slice that imported the shared root and `target` is the file in the other universe. The baseline key stays `ruleId|file|fromLayer|toLayer|target` and does not include `reasonId`. A shared hop that stays inside one universe is not this finding. The direct shared-root hop stays the `SHARED_IMPORTS_SLICE` warning. `"deny"` is unchanged and does not emit this reason. Doctor slice counts stay on `CROSS_PARENT_SLICE` and `CROSS_SIBLING_SLICE`. **ark-check and CI report this path. The write hook and ESLint see one edge at a time and do not block it.** arkgate 4.8.22 and older reject `"deny-cross-parent"` at config load.
117
122
 
118
123
  <a id="LAYER_INTENT_REFERENCE_VIOLATION"></a>
119
124
 
@@ -904,6 +909,33 @@ never opting out of knowing.
904
909
  - **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
910
  - **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
911
 
912
+ <a id="CONFIG_CHILD_SLICES_VERSION"></a>
913
+
914
+ ### `CONFIG_CHILD_SLICES_VERSION`
915
+
916
+ **childSlices needs a newer arkgate**
917
+
918
+ - **Why:** The rule schema sets additionalProperties to false. arkgate 4.8.22 and older reject a config that contains childSlices instead of ignoring the key.
919
+ - **Fix:** Pin arkgate newer than 4.8.22 before shipping a config that sets childSlices. This warning does not fail the check.
920
+
921
+ <a id="CONFIG_CHILD_SLICE_EXTENDS"></a>
922
+
923
+ ### `CONFIG_CHILD_SLICE_EXTENDS`
924
+
925
+ **Child slice id does not extend its universe**
926
+
927
+ - **Why:** A path resolved a child id that is not the universe id plus a further segment. The child wall does not treat that id as a child, so the edge is universe common until the folders line up.
928
+ - **Fix:** Point childSlices.sliceFolders at children under the same universe id the outer sliceFolders already names. Doctor names the path. Advisory — it does not fail the check.
929
+
930
+ <a id="CONFIG_CHILD_SLICE_CROSS_UNIVERSE"></a>
931
+
932
+ ### `CONFIG_CHILD_SLICE_CROSS_UNIVERSE`
933
+
934
+ **Child slice allowance cannot cross the universe wall**
935
+
936
+ - **Why:** childSlices.allowedCrossSlice names a pattern that can match two universes. That list clears only a sibling crossing inside one universe. The universe wall still denies the edge.
937
+ - **Fix:** Narrow the pattern so both sides share one universe prefix (features/projects/* to features/projects/d2d-item), or remove the entry. This warning does not fail the check.
938
+
907
939
  ## Meta
908
940
 
909
941
  <a id="ARK_UNKNOWN"></a>
@@ -80,7 +80,7 @@ On the seven lane openings — `docs/use.md`, `docs/develop.md`, `docs/README.md
80
80
  `README.md` is the first-contact module. Its first screen is four beats: what
81
81
  (**Contener · Guiar · Ordenar**), why (design the boundary before you implement;
82
82
  a green check is **needs a refactor** when leftover mess remains), one command
83
- (`npx arkgate@4.8.22 start`), and one honest red result (fail-open named; required
83
+ (`npx arkgate@4.8.23 start`), and one honest red result (fail-open named; required
84
84
  CI is the hard line). The four paragraphs, the not-that line, the host matrix,
85
85
  and the release index sit below `## Appendix`. The not-that line does not lead
86
86
  the README.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arkgate",
3
- "version": "4.8.22",
3
+ "version": "4.8.23",
4
4
  "description": "When the agent writes a bad import, the write doesn’t land. The same check fails the pull request.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -840,8 +840,130 @@
840
840
  "sharedImportsSlice": {
841
841
  "type": "string",
842
842
  "enum": [
843
- "deny"
844
- ]
843
+ "deny",
844
+ "deny-cross-parent"
845
+ ],
846
+ "description": "deny blocks every shared-root import of a slice. deny-cross-parent leaves that hop as a warning and, in ark-check and CI only, reports a slice that reaches another universe through a shared root. The write hook and ESLint see one edge and do not block it. arkgate 4.8.22 and older reject deny-cross-parent."
847
+ },
848
+ "childSlices": {
849
+ "type": "object",
850
+ "additionalProperties": false,
851
+ "required": [
852
+ "sliceFolders"
853
+ ],
854
+ "description": "Optional inner wall under this rule. Absent keeps today's universe wall. sliceFolders names children. commonFolders and flat files are universe common. siblings is \"deny\" (default), \"advisory\", or { default, enforce }. parentMayImportChild defaults to false. allowedCrossSlice may use a whole-segment *. It clears only a sibling crossing. Cross-parent has no advisory knob. arkgate 4.8.22 and older reject this key. A build that still rejects unknown childSlices fields rejects allowedCrossSlice at config load. A build that still types siblings as a string enum rejects the object at config load.",
855
+ "properties": {
856
+ "sliceFolders": {
857
+ "type": "array",
858
+ "items": {
859
+ "type": "string",
860
+ "minLength": 1
861
+ },
862
+ "uniqueItems": true,
863
+ "minItems": 1
864
+ },
865
+ "sliceIdentity": {
866
+ "type": "string",
867
+ "enum": [
868
+ "path",
869
+ "stars"
870
+ ]
871
+ },
872
+ "commonFolders": {
873
+ "type": "array",
874
+ "items": {
875
+ "type": "string",
876
+ "minLength": 1
877
+ },
878
+ "uniqueItems": true,
879
+ "minItems": 1
880
+ },
881
+ "siblings": {
882
+ "description": "\"deny\" or \"advisory\", or { default, enforce } so listed subtrees are errors while the default stays advisory. A string-enum build rejects the object at config load (must be one of deny, advisory).",
883
+ "oneOf": [
884
+ {
885
+ "type": "string",
886
+ "enum": [
887
+ "deny",
888
+ "advisory"
889
+ ]
890
+ },
891
+ {
892
+ "type": "object",
893
+ "additionalProperties": false,
894
+ "required": [
895
+ "default"
896
+ ],
897
+ "properties": {
898
+ "default": {
899
+ "type": "string",
900
+ "enum": [
901
+ "deny",
902
+ "advisory"
903
+ ]
904
+ },
905
+ "enforce": {
906
+ "type": "array",
907
+ "items": {
908
+ "type": "string",
909
+ "minLength": 1
910
+ },
911
+ "uniqueItems": true
912
+ }
913
+ }
914
+ }
915
+ ]
916
+ },
917
+ "parentMayImportChild": {
918
+ "type": "boolean"
919
+ },
920
+ "sliceAliases": {
921
+ "type": "array",
922
+ "minItems": 1,
923
+ "description": "Maps a source path glob onto a child slice id (universe id plus one child segment) so files outside the slice trees take that universe and child for both walls. A bare name, a universe id alone, an unknown universe, and a wildcard in to are rejected. The glob may not overlap a slice folder, and two aliases may not match the same file. Doctor lists each alias as an owed move. A build that rejects unknown childSlices fields fails at config load (unknown field). arkgate 4.8.22 and older reject childSlices.",
924
+ "items": {
925
+ "type": "object",
926
+ "additionalProperties": false,
927
+ "required": [
928
+ "from",
929
+ "to"
930
+ ],
931
+ "properties": {
932
+ "from": {
933
+ "type": "string",
934
+ "minLength": 1
935
+ },
936
+ "to": {
937
+ "type": "string",
938
+ "minLength": 1
939
+ }
940
+ }
941
+ }
942
+ },
943
+ "allowedCrossSlice": {
944
+ "type": "array",
945
+ "minItems": 1,
946
+ "description": "Directed child-slice allowances. * matches one whole path segment (features/projects/*). ** and a partial segment are rejected. A bare name is rejected. This list clears only CROSS_SIBLING_SLICE. It cannot clear CROSS_PARENT_SLICE or CROSS_PARENT_VIA_SHARED. The universe allowedCrossSlice still treats * as a literal. A build that rejects unknown childSlices fields fails at config load (unknown field).",
947
+ "items": {
948
+ "type": "object",
949
+ "additionalProperties": false,
950
+ "required": [
951
+ "from",
952
+ "to"
953
+ ],
954
+ "properties": {
955
+ "from": {
956
+ "type": "string",
957
+ "minLength": 1
958
+ },
959
+ "to": {
960
+ "type": "string",
961
+ "minLength": 1
962
+ }
963
+ }
964
+ }
965
+ }
966
+ }
845
967
  }
846
968
  }
847
969
  },
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.22",
9
+ "version": "4.8.23",
10
10
  "packages": [
11
11
  {
12
12
  "registryType": "npm",
13
13
  "identifier": "arkgate",
14
- "version": "4.8.22",
14
+ "version": "4.8.23",
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.22**
12
+ Package version when last generated context: **arkgate@4.8.23**
13
13
  Schema: agent-skills package contract `1.0`
14
14
 
15
15
  ## Skills (closed catalog)