arkgate 4.8.19 → 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.
Files changed (85) hide show
  1. package/CHANGELOG.md +220 -0
  2. package/README.md +107 -117
  3. package/bin/ark-check-runtime.mjs +26 -4
  4. package/bin/ark-layer-match.mjs +236 -12
  5. package/bin/ark.mjs +6 -2
  6. package/bin/lib/analysis-engine.mjs +13 -6
  7. package/bin/lib/config-contract.mjs +6 -0
  8. package/bin/lib/diagnostic-catalog.mjs +1 -0
  9. package/bin/lib/doctor-advisories.mjs +22 -1
  10. package/bin/lib/doctor-human.mjs +11 -9
  11. package/bin/lib/doctor-plan.mjs +17 -14
  12. package/bin/lib/enforcement-honesty.mjs +30 -2
  13. package/bin/lib/first-run-help.mjs +7 -1
  14. package/bin/lib/html-report-advisories.mjs +8 -0
  15. package/bin/lib/html-report-depth.mjs +12 -7
  16. package/bin/lib/invariant-coverage.mjs +406 -54
  17. package/bin/lib/managed-upgrade.mjs +59 -14
  18. package/bin/lib/package-manager.mjs +5 -2
  19. package/bin/lib/physical-cohesion.mjs +68 -51
  20. package/bin/lib/pilot-loop.mjs +183 -37
  21. package/bin/lib/reshape-decisions.mjs +2 -2
  22. package/bin/lib/rules-under-contract.mjs +40 -4
  23. package/bin/lib/start-install-recovery.mjs +156 -0
  24. package/bin/lib/start-preview.mjs +0 -54
  25. package/bin/lib/upgrade-behavior-changes.mjs +83 -0
  26. package/bin/lib/upgrade-command.mjs +69 -31
  27. package/bin/lib/upgrade-outcome.mjs +359 -0
  28. package/bin/lib/violations.mjs +109 -0
  29. package/dist/{configTypes-VD0qcubY.d.ts → configTypes-CTELo87-.d.ts} +9 -0
  30. package/dist/{diagnosticCatalog-D2v0ASN2.d.ts → diagnosticCatalog-B7BXlet6.d.ts} +79 -5
  31. package/dist/eslint/index.cjs +4 -4
  32. package/dist/eslint/index.d.ts +35 -4
  33. package/dist/eslint/index.js +4 -4
  34. package/dist/index.cjs +25 -18
  35. package/dist/index.d.ts +13 -4
  36. package/dist/index.js +27 -20
  37. package/dist/nestjs/index.cjs +9 -9
  38. package/dist/nestjs/index.d.ts +3 -3
  39. package/dist/nestjs/index.js +9 -9
  40. package/dist/runtime/index.cjs +18 -11
  41. package/dist/runtime/index.d.ts +6 -6
  42. package/dist/runtime/index.js +18 -11
  43. package/dist/{types-D5GT5ZT8.d.ts → types-fQ9-KrBj.d.ts} +1 -1
  44. package/dist/{types-BSzRy2X1.d.ts → types-yDNEQ603.d.ts} +1 -1
  45. package/docs/README.md +4 -3
  46. package/docs/agent-guide.md +15 -7
  47. package/docs/brownfield-adoption.md +4 -3
  48. package/docs/configuration.md +46 -8
  49. package/docs/develop.md +1 -1
  50. package/docs/diagnostics.md +12 -2
  51. package/docs/package-surface.md +4 -3
  52. package/docs/product-voice.md +11 -3
  53. package/docs/use.md +1 -1
  54. package/package.json +3 -3
  55. package/schemas/ark.config.schema.json +14 -0
  56. package/server.json +2 -2
  57. package/templates/agent-skills/README.md +1 -1
  58. package/templates/agent-skills/ark-adopt/SKILL.md +18 -1
  59. package/templates/agent-skills/ark-architect/SKILL.md +2 -0
  60. package/templates/agent-skills/ark-autopilot/SKILL.md +6 -2
  61. package/templates/agent-skills/ark-contract/SKILL.md +2 -0
  62. package/templates/agent-skills/ark-coverage/SKILL.md +3 -1
  63. package/templates/agent-skills/ark-explain/SKILL.md +3 -1
  64. package/templates/agent-skills/ark-explore/SKILL.md +15 -1
  65. package/templates/agent-skills/ark-fix/SKILL.md +2 -0
  66. package/templates/agent-skills/ark-loop/SKILL.md +2 -0
  67. package/templates/agent-skills/ark-order/SKILL.md +2 -0
  68. package/templates/agent-skills/ark-place/SKILL.md +2 -0
  69. package/templates/agent-skills/ark-runtime/SKILL.md +2 -0
  70. package/templates/agent-skills/ark-think/SKILL.md +2 -0
  71. package/templates/agent-skills/ark-upgrade/SKILL.md +25 -10
  72. package/templates/skills/ark-adopt.md +18 -1
  73. package/templates/skills/ark-architect.md +2 -0
  74. package/templates/skills/ark-autopilot.md +6 -2
  75. package/templates/skills/ark-contract.md +2 -0
  76. package/templates/skills/ark-coverage.md +3 -1
  77. package/templates/skills/ark-explain.md +3 -1
  78. package/templates/skills/ark-explore.md +15 -1
  79. package/templates/skills/ark-fix.md +2 -0
  80. package/templates/skills/ark-loop.md +2 -0
  81. package/templates/skills/ark-order.md +2 -0
  82. package/templates/skills/ark-place.md +2 -0
  83. package/templates/skills/ark-runtime.md +2 -0
  84. package/templates/skills/ark-think.md +2 -0
  85. package/templates/skills/ark-upgrade.md +25 -10
@@ -53,6 +53,11 @@ one bounded decision needs 2–3 enforceable options.
53
53
  `coverage.coverageRoots` on the folder the test runner uses. Fail-closed.
54
54
  `testGlobs` alone is not enough. Silent when no invariant is enforced.
55
55
  Handoff `/ark-adopt` to write the roots. No new skill.
56
+ - When an invariant declares `coverage.symbol`, read the witness path
57
+ (`symbolEvidenceFile`) and the discard line on doctor and `--rules-inventory`,
58
+ including when the run is green. A declaration in a non-test file is not
59
+ “the tests pass” — ArkGate never runs tests. Depth and byte caps stay
60
+ internal; the counts are what you read.
56
61
  - A doctor green / Healthy line must name a file, config key, or test.
57
62
  Uncited green is a lie — treat it as unfinished. No `/ark-cite`.
58
63
  - Distinguish **missing** skills vs **stale** catalog. Installed ≠ stale.
@@ -345,12 +350,19 @@ targets as explicit adopter decisions, not residual to re-fight. Keep their mirr
345
350
  map. When the user accepts, defers, or rejects a live `reshapePilot.nextPilot`, record the card's
346
351
  exact `decisionTarget` with a reason (and optional `reviewBy`) in
347
352
  `.ark/reshape-decisions.json`. Never infer or suppress from free-form golden-pattern prose.
353
+ A proposed `to` stays under the source anchor (`concept/`) and is kept only when that path
354
+ stays in the same layer and the same slice id. If no governed destination keeps both,
355
+ `nextPilot` is null — do not invent a folder outside the contract. Success is a smaller
356
+ cluster with the layer and slice id unchanged and the card still proposed; a green gate is
357
+ not success. A cohesion residual (`physical-cohesion-residual`) starts that one reshape
358
+ judgment card as `pilotLoop.nextPilot`. It does not start the pattern-bet apply
359
+ loop. Apply that one card, then re-doctor.
348
360
 
349
361
  ### C. Coupling & debt (measure, don’t guess)
350
362
  Prefer evidence over aesthetics:
351
363
  - **Fan-in / importers** of hot modules (who imports the suspect file?).
352
364
  - **Export surface** (how many public symbols does the orchestration module re-export?).
353
- - Import cycles, cross-feature leaks (`peerIsolation` candidates).
365
+ - Import cycles, cross-feature leaks (`peerIsolation` candidates). A shared root that imports a slice is a direct-only bridge; doctor lists it. `sharedImportsSlice: "deny"` closes that one hop. It does not finish the wall.
354
366
  - Business rules in UI/hooks (`can*`, `calculate*`, policy constants) → Domain / intents.
355
367
  - Dead or aspirational globs; layers with files but no rules; **starter/preset rules weaker than sibling archetypes** (soft green).
356
368
  - LOC is a **hint** only — pair it with fan-in or export count before calling something a god module.
@@ -522,5 +534,7 @@ End with **exactly** these headings (markdown `###`):
522
534
  - **Handoff:** `/ark-…` / CLI / `none`
523
535
  - **Incomplete?** `no` | `yes — <what is missing>`
524
536
 
537
+ When `doctor.productHonesty.finished` is `false`, **Incomplete? no** is disallowed. Write `yes — <pilotLoop.extractionCard.move or residual>`.
538
+
525
539
  If a **STOP** handoff applies and you continued as if done, set **Incomplete?** to `yes`.
526
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`. Stop and obtain user consent before using it.
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. |
@@ -259,9 +266,11 @@ ArkGate has **always-on Layers** plus opt-in extras. The user chooses extras; yo
259
266
  If already current (`ALREADY_CURRENT`), retain the read-only preview and still read `whatsNew`
260
267
  + `skillDrift`.
261
268
 
262
- For pnpm repositories with `minimumReleaseAge`, use the repository's existing
263
- trusted first-party exception mechanism when the new release is still cooling
264
- off, and prove `pnpm install --frozen-lockfile` succeeds.
269
+ For pnpm repositories with `minimumReleaseAge`, put the exception on
270
+ `minimumReleaseAgeExclude` in pnpm config or `pnpm-workspace.yaml` (a CLI
271
+ flag is not enough) when the new release is still cooling off, or keep using
272
+ `npx --package=arkgate@<pin>` until the package is mature. Prove
273
+ `pnpm install --frozen-lockfile` succeeds after a local add.
265
274
 
266
275
  4. **Apply only the reviewed candidate.** When there are no blocked assets, run
267
276
  the preview's **exact** `nextCommand` as emitted (JSON field / human “Apply the
@@ -283,16 +292,19 @@ ArkGate has **always-on Layers** plus opt-in extras. The user chooses extras; yo
283
292
  (unless more deliberate refreshes remain).
284
293
 
285
294
  5. **Verify enforcement and architecture (post-upgrade checks).** Read apply JSON
286
- `postUpgradeChecks` when present. Also run:
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:
287
297
  `npx arkgate-check --doctor --json` (or the project-local `ark-check`) and
288
298
  the same fail-closed architecture command used by managed apply (normally
289
299
  `npx arkgate-check --root . --config ark.config.json --strict-merge --json`).
290
- Require `completeness: "complete"` and `ok: true`. Confirm `doctor.improvementCompass` and
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
291
304
  `doctor.deepModuleCoach` honesty. Run `npx arkgate agents-md --check` and
292
305
  `npx arkgate status --json`. If MCP was used, restart MCP after package bump and re-bind
293
306
  identity. Treat provider-unavailable CI required-check evidence as `unverified`, never as proof
294
- that merges are blocked. If new violations appear, hand off to `/ark-autopilot`; do not regenerate a baseline without
295
- explicit approval.
307
+ that merges are blocked.
296
308
 
297
309
  ## Active host vs deferred hosts
298
310
 
@@ -330,5 +342,8 @@ End with exactly this structure:
330
342
  - **Handoff:** `/ark-…`, CLI action, or `none`
331
343
  - **Incomplete?** `no` or `yes — <missing work>`
332
344
 
345
+ When `doctor.productHonesty.finished` is `false`, **Incomplete? no** is disallowed. Write `yes — <pilotLoop.extractionCard.move or residual>`.
346
+
333
347
  If a required verification did not run or a conflict remains blocked, report the
334
- task incomplete. Deferred hosts (including Codex when inactive) never make Incomplete? yes.
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.
@@ -63,6 +63,11 @@ has honest houses. Skills never enforce — CLI / hooks / CI do.
63
63
  `coverage.coverageRoots` to the folder the test runner uses. Fail-closed
64
64
  until that path exists. `coverage.testGlobs` alone is not enough. Silent
65
65
  when no invariant is enforced. No new skill.
66
+ - `coverage.symbol` means a declaration of that identifier in a non-test file.
67
+ Doctor and `--rules-inventory` print `symbolEvidenceFile` and the discard
68
+ counts even when uncovered is 0. Read that path. Imports and calls in tests
69
+ do not count. That declaration text is not “the tests pass” — ArkGate never
70
+ runs tests. No new config key.
66
71
  - CLI-first: if `arkgate-check` already resolved the root, do not wait on MCP.
67
72
  - Do not add `arkRun` or `arkOrder` unless the user wants that extra. When they do, write
68
73
  **advisory** extra in this turn (`arkRun` schema `1.2+`; `arkOrder` schema `1.3+`).
@@ -353,8 +358,18 @@ Ark protects the **boundary around** a framework, not its internals. Nest/DI pub
353
358
  The denial names its reason. `unclassifiable path` in bulk means shared code lives outside
354
359
  the slice folders — declare those roots (`sharedRoots`) on the rule instead of treating
355
360
  thousands of shared files as violations; `cross-slice edge a → b` is the real one, and a
356
- deliberate directed edge goes in `allowedCrossSlice`. Promoting the shared slice to its own
361
+ deliberate directed edge goes in `allowedCrossSlice`. Shared roots are a sink: a slice may
362
+ import them, and they may import a slice. Doctor lists that shared-root → slice hop even
363
+ when the check stays green, so the wall is direct-only. `sharedImportsSlice: "deny"` closes
364
+ that one hop; it does not finish the wall. Promoting the shared slice to its own
357
365
  layer is still the preferred fix.
366
+ `sliceFolders`: a bare name stays an unanchored one-segment match (`features` on
367
+ `src/lib/features/projects/rfi/x.ts` is `features/projects`); a filename is never the
368
+ child segment. A starred prefix (`lib/features/*/*`) is anchored like `sharedRoots`
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
372
+ feature-to-feature import and expect `cross-slice`.
358
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).
359
374
  Empty Domain/Persistence + I/O under Application → false-green.
360
375
  **STOP — do not continue this skill as complete.** **STOP — false-green:** fix the config **in this turn** before claiming ENFORCE. Do not claim goal.met / ENFORCE from type-only cleanup while doctor reports `contract-false-green-io-under-application`.
@@ -423,5 +438,7 @@ End with **exactly** these headings (markdown `###`):
423
438
  - **Handoff:** `/ark-…` / CLI / `none`
424
439
  - **Incomplete?** `no` | `yes — <what is missing>`
425
440
 
441
+ When `doctor.productHonesty.finished` is `false`, **Incomplete? no** is disallowed. Write `yes — <pilotLoop.extractionCard.move or residual>`.
442
+
426
443
  If a **STOP** handoff applies and you continued as if done, set **Incomplete?** to `yes`.
427
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,8 +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
-
114
-
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.
115
117
 
116
118
  ## MCP workspace binding (mandatory)
117
119
 
@@ -306,5 +308,7 @@ End with **exactly** these headings (markdown `###`):
306
308
  - **Handoff:** `/ark-…` / CLI / `none`
307
309
  - **Incomplete?** `no` | `yes — <what is missing>`
308
310
 
311
+ When `doctor.productHonesty.finished` is `false`, **Incomplete? no** is disallowed. Write `yes — <pilotLoop.extractionCard.move or residual>`.
312
+
309
313
  If a **STOP** handoff applies and you continued as if done, set **Incomplete?** to `yes`.
310
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>`.
@@ -96,7 +96,7 @@ ArkGate has **always-on Layers** plus opt-in extras. The user chooses extras; yo
96
96
  3. Absence of `arkRules` is **valid** — do not force ArkRules unless the user wants them or residual inventory clearly wants a pilot.
97
97
  4. Editing `arkrules/*` or promoting modes is **`/ark-adopt`**; fixing code under a structure sensor is **`/ark-autopilot`** (judgment, never invent mechanical-safe).
98
98
  5. CLI helpers: `ark-check --rules-inventory --json`, doctor JSON `rulesUnderContract`, sensors emit `ARKRULE_*` / `INVARIANT_UNCOVERED` / `INVARIANT_CATALOG_EMPTY` with `evidence.arkruleId`.
99
- 5b. Invariant coverage is a **text match, never an execution**: a file walk plus the invariant id in a `describe`/`it` title. Never report `INVARIANT_UNCOVERED: 0` as “the tests pass” or “the tests run” — ArkGate does not run tests and reads no runner config. When the project declares `coverage.coverageRoots`, a covering test found outside them raises the advisory `INVARIANT_COVERAGE_OUTSIDE_ROOTS`; without that declaration ArkGate makes no claim about where tests run. Adopted + catalogued invariants without `coverage.testGlobs` or `coverage.coverageRoots` fails closed (`INVARIANT_TESTS_PATH_MISSING`) — write the path (`/ark-adopt`). When any invariant is enforced, missing `coverage.coverageRoots` fails closed (`INVARIANT_COVERAGE_ROOTS_MISSING`) — write the runner roots (`/ark-adopt`). `testGlobs` alone is not enough.
99
+ 5b. Invariant coverage is a **text match, never an execution**: a file walk plus the invariant id in a `describe`/`it` title. `coverage.symbol` means a declaration of that identifier in a non-test file (`symbolEvidenceFile`); imports and test calls do not count. Doctor and `--rules-inventory` print that witness path and the scan discard counts on a green run too. Never report `INVARIANT_UNCOVERED: 0`, a witness path, or a discard line as “the tests pass” or “the tests run” — ArkGate does not run tests and reads no runner config. Declaration text is not “the tests pass.” When the project declares `coverage.coverageRoots`, a covering test found outside them raises the advisory `INVARIANT_COVERAGE_OUTSIDE_ROOTS`; without that declaration ArkGate makes no claim about where tests run. Adopted + catalogued invariants without `coverage.testGlobs` or `coverage.coverageRoots` fails closed (`INVARIANT_TESTS_PATH_MISSING`) — write the path (`/ark-adopt`). When any invariant is enforced, missing `coverage.coverageRoots` fails closed (`INVARIANT_COVERAGE_ROOTS_MISSING`) — write the runner roots (`/ark-adopt`). `testGlobs` alone is not enough.
100
100
  6. Extras silent when off. Doctor `arkRun` / `arkOrder` is `notAScore`. Do not force extras. Wire one kernel candidate via `/ark-runtime`; one order-plane candidate via `/ark-order`. Do not invent `/ark-run`.
101
101
 
102
102
 
@@ -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.
@@ -188,7 +188,7 @@ else is judgment/deferred and must not be auto-applied.
188
188
  **Type-edge honesty:** type-only denied edges are **placement debt** (`typeOnly` +
189
189
  `failsStrict: false`) — prefer SharedTypes / owning layer; they do not fail merge like value
190
190
  edges. Doctor `productHonesty` and `violations.typeEdgePolicy` must not be sold as “all done”
191
- when residual signals remain.
191
+ when residual signals remain (`physical-cohesion-residual` included).
192
192
 
193
193
  ## Spoken / written explanation
194
194
 
@@ -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
 
@@ -53,6 +53,11 @@ one bounded decision needs 2–3 enforceable options.
53
53
  `coverage.coverageRoots` on the folder the test runner uses. Fail-closed.
54
54
  `testGlobs` alone is not enough. Silent when no invariant is enforced.
55
55
  Handoff `/ark-adopt` to write the roots. No new skill.
56
+ - When an invariant declares `coverage.symbol`, read the witness path
57
+ (`symbolEvidenceFile`) and the discard line on doctor and `--rules-inventory`,
58
+ including when the run is green. A declaration in a non-test file is not
59
+ “the tests pass” — ArkGate never runs tests. Depth and byte caps stay
60
+ internal; the counts are what you read.
56
61
  - A doctor green / Healthy line must name a file, config key, or test.
57
62
  Uncited green is a lie — treat it as unfinished. No `/ark-cite`.
58
63
  - Distinguish **missing** skills vs **stale** catalog. Installed ≠ stale.
@@ -345,12 +350,19 @@ targets as explicit adopter decisions, not residual to re-fight. Keep their mirr
345
350
  map. When the user accepts, defers, or rejects a live `reshapePilot.nextPilot`, record the card's
346
351
  exact `decisionTarget` with a reason (and optional `reviewBy`) in
347
352
  `.ark/reshape-decisions.json`. Never infer or suppress from free-form golden-pattern prose.
353
+ A proposed `to` stays under the source anchor (`concept/`) and is kept only when that path
354
+ stays in the same layer and the same slice id. If no governed destination keeps both,
355
+ `nextPilot` is null — do not invent a folder outside the contract. Success is a smaller
356
+ cluster with the layer and slice id unchanged and the card still proposed; a green gate is
357
+ not success. A cohesion residual (`physical-cohesion-residual`) starts that one reshape
358
+ judgment card as `pilotLoop.nextPilot`. It does not start the pattern-bet apply
359
+ loop. Apply that one card, then re-doctor.
348
360
 
349
361
  ### C. Coupling & debt (measure, don’t guess)
350
362
  Prefer evidence over aesthetics:
351
363
  - **Fan-in / importers** of hot modules (who imports the suspect file?).
352
364
  - **Export surface** (how many public symbols does the orchestration module re-export?).
353
- - Import cycles, cross-feature leaks (`peerIsolation` candidates).
365
+ - Import cycles, cross-feature leaks (`peerIsolation` candidates). A shared root that imports a slice is a direct-only bridge; doctor lists it. `sharedImportsSlice: "deny"` closes that one hop. It does not finish the wall.
354
366
  - Business rules in UI/hooks (`can*`, `calculate*`, policy constants) → Domain / intents.
355
367
  - Dead or aspirational globs; layers with files but no rules; **starter/preset rules weaker than sibling archetypes** (soft green).
356
368
  - LOC is a **hint** only — pair it with fan-in or export count before calling something a god module.
@@ -522,5 +534,7 @@ End with **exactly** these headings (markdown `###`):
522
534
  - **Handoff:** `/ark-…` / CLI / `none`
523
535
  - **Incomplete?** `no` | `yes — <what is missing>`
524
536
 
537
+ When `doctor.productHonesty.finished` is `false`, **Incomplete? no** is disallowed. Write `yes — <pilotLoop.extractionCard.move or residual>`.
538
+
525
539
  If a **STOP** handoff applies and you continued as if done, set **Incomplete?** to `yes`.
526
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`. Stop and obtain user consent before using it.
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. |
@@ -259,9 +266,11 @@ ArkGate has **always-on Layers** plus opt-in extras. The user chooses extras; yo
259
266
  If already current (`ALREADY_CURRENT`), retain the read-only preview and still read `whatsNew`
260
267
  + `skillDrift`.
261
268
 
262
- For pnpm repositories with `minimumReleaseAge`, use the repository's existing
263
- trusted first-party exception mechanism when the new release is still cooling
264
- off, and prove `pnpm install --frozen-lockfile` succeeds.
269
+ For pnpm repositories with `minimumReleaseAge`, put the exception on
270
+ `minimumReleaseAgeExclude` in pnpm config or `pnpm-workspace.yaml` (a CLI
271
+ flag is not enough) when the new release is still cooling off, or keep using
272
+ `npx --package=arkgate@<pin>` until the package is mature. Prove
273
+ `pnpm install --frozen-lockfile` succeeds after a local add.
265
274
 
266
275
  4. **Apply only the reviewed candidate.** When there are no blocked assets, run
267
276
  the preview's **exact** `nextCommand` as emitted (JSON field / human “Apply the
@@ -283,16 +292,19 @@ ArkGate has **always-on Layers** plus opt-in extras. The user chooses extras; yo
283
292
  (unless more deliberate refreshes remain).
284
293
 
285
294
  5. **Verify enforcement and architecture (post-upgrade checks).** Read apply JSON
286
- `postUpgradeChecks` when present. Also run:
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:
287
297
  `npx arkgate-check --doctor --json` (or the project-local `ark-check`) and
288
298
  the same fail-closed architecture command used by managed apply (normally
289
299
  `npx arkgate-check --root . --config ark.config.json --strict-merge --json`).
290
- Require `completeness: "complete"` and `ok: true`. Confirm `doctor.improvementCompass` and
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
291
304
  `doctor.deepModuleCoach` honesty. Run `npx arkgate agents-md --check` and
292
305
  `npx arkgate status --json`. If MCP was used, restart MCP after package bump and re-bind
293
306
  identity. Treat provider-unavailable CI required-check evidence as `unverified`, never as proof
294
- that merges are blocked. If new violations appear, hand off to `/ark-autopilot`; do not regenerate a baseline without
295
- explicit approval.
307
+ that merges are blocked.
296
308
 
297
309
  ## Active host vs deferred hosts
298
310
 
@@ -330,5 +342,8 @@ End with exactly this structure:
330
342
  - **Handoff:** `/ark-…`, CLI action, or `none`
331
343
  - **Incomplete?** `no` or `yes — <missing work>`
332
344
 
345
+ When `doctor.productHonesty.finished` is `false`, **Incomplete? no** is disallowed. Write `yes — <pilotLoop.extractionCard.move or residual>`.
346
+
333
347
  If a required verification did not run or a conflict remains blocked, report the
334
- task incomplete. Deferred hosts (including Codex when inactive) never make Incomplete? yes.
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.