arkgate 4.2.0 → 4.3.0

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 (46) hide show
  1. package/CHANGELOG.md +86 -4
  2. package/README.md +20 -6
  3. package/bin/ark-mcp-runtime.mjs +64 -0
  4. package/bin/ark-shared.mjs +16 -4
  5. package/bin/ark.mjs +55 -1
  6. package/bin/lib/adapter-contract.mjs +88 -5
  7. package/bin/lib/agent-projection-command.mjs +396 -0
  8. package/bin/lib/agent-projection.mjs +319 -0
  9. package/bin/lib/agent-skills-package.mjs +266 -0
  10. package/bin/lib/baseline-key.mjs +32 -0
  11. package/bin/lib/ci-and-commands.mjs +44 -0
  12. package/bin/lib/diagnostic-catalog.mjs +155 -0
  13. package/bin/lib/physical-cohesion.mjs +2 -1
  14. package/bin/lib/status-command.mjs +369 -0
  15. package/bin/lib/status-manifest.mjs +394 -0
  16. package/dist/eslint/index.cjs +3 -3
  17. package/dist/eslint/index.js +3 -3
  18. package/dist/index.cjs +46 -11
  19. package/dist/index.d.ts +729 -6
  20. package/dist/index.js +46 -11
  21. package/docs/README.md +6 -6
  22. package/docs/agent-guide.md +112 -14
  23. package/docs/configuration.md +7 -0
  24. package/docs/develop.md +8 -0
  25. package/docs/diagnostics.md +606 -0
  26. package/docs/package-surface.md +19 -8
  27. package/docs/product-voice.md +45 -0
  28. package/docs/use.md +23 -0
  29. package/package.json +11 -1
  30. package/schemas/ark.analysis-result.schema.json +14 -1
  31. package/schemas/ark.status-manifest.schema.json +244 -0
  32. package/server.json +2 -2
  33. package/templates/agent-skills/README.md +59 -0
  34. package/templates/agent-skills/ark-adopt/SKILL.md +171 -0
  35. package/templates/agent-skills/ark-architect/SKILL.md +175 -0
  36. package/templates/agent-skills/ark-autopilot/SKILL.md +242 -0
  37. package/templates/agent-skills/ark-contract/SKILL.md +136 -0
  38. package/templates/agent-skills/ark-coverage/SKILL.md +167 -0
  39. package/templates/agent-skills/ark-explain/SKILL.md +210 -0
  40. package/templates/agent-skills/ark-explore/SKILL.md +377 -0
  41. package/templates/agent-skills/ark-fix/SKILL.md +185 -0
  42. package/templates/agent-skills/ark-loop/SKILL.md +180 -0
  43. package/templates/agent-skills/ark-place/SKILL.md +162 -0
  44. package/templates/agent-skills/ark-runtime/SKILL.md +120 -0
  45. package/templates/agent-skills/ark-think/SKILL.md +133 -0
  46. package/templates/agent-skills/ark-upgrade/SKILL.md +218 -0
@@ -0,0 +1,606 @@
1
+ # ArkGate diagnostic code catalog
2
+
3
+ > **Source of truth:** Domain module `src/domain/diagnosticCatalog.ts` (ACS02).
4
+ > Generated CLI mirror: `bin/lib/diagnostic-catalog.mjs`. Catalog schema `1.0`.
5
+ > Enforcement remains CLI / hooks / CI — this page is documentation only.
6
+
7
+ Every public `ruleId` ArkGate emits is listed below with **why** (contract intent) and **fix** (canonical next step).
8
+ Live adapter JSON may specialize `nextAction` for evidence (e.g. type-only layer imports); the catalog fix is the stable docs anchor.
9
+
10
+ Programmatic API (stable root export):
11
+
12
+ ```ts
13
+ import {
14
+ DIAGNOSTIC_CATALOG,
15
+ getDiagnosticCatalogEntry,
16
+ diagnosticDocsPath,
17
+ isKnownDiagnosticCode,
18
+ } from "arkgate";
19
+ ```
20
+
21
+ Link form for agents: `docs/diagnostics.md#RULE_ID` (exact-case HTML anchors below).
22
+
23
+ ## Index
24
+
25
+ | ruleId | Category | Title |
26
+ |--------|----------|-------|
27
+ | [`LAYER_IMPORT_VIOLATION`](#LAYER_IMPORT_VIOLATION) | layer | Layer import not allowed |
28
+ | [`LAYER_INTENT_REFERENCE_VIOLATION`](#LAYER_INTENT_REFERENCE_VIOLATION) | layer | Intent referenced across a blocked layer edge |
29
+ | [`LAYER_REFERENCE_VIOLATION`](#LAYER_REFERENCE_VIOLATION) | layer | Layer reference blocked (snippet / AI gate) |
30
+ | [`CIRCULAR_DEPENDENCY`](#CIRCULAR_DEPENDENCY) | layer | Dependency cycle |
31
+ | [`FORBIDDEN_GLOBAL`](#FORBIDDEN_GLOBAL) | capability | Forbidden ambient global or dual import |
32
+ | [`CAPABILITY_VIOLATION`](#CAPABILITY_VIOLATION) | capability | Denied effect capability |
33
+ | [`RAW_EVENT_PUBLISH`](#RAW_EVENT_PUBLISH) | publish | Raw event publish |
34
+ | [`PUBLISH_MISSING_SOURCE`](#PUBLISH_MISSING_SOURCE) | publish | Publish missing metadata.source |
35
+ | [`PUBLISH_SOURCE_LAYER_MISMATCH`](#PUBLISH_SOURCE_LAYER_MISMATCH) | publish | Publish source layer mismatch |
36
+ | [`UNKNOWN_INTENT`](#UNKNOWN_INTENT) | publish | Unknown intent reference |
37
+ | [`DYNAMIC_IMPORT_NOT_ALLOWLISTED`](#DYNAMIC_IMPORT_NOT_ALLOWLISTED) | safety | Non-literal dynamic import |
38
+ | [`DYNAMIC_REQUIRE_NOT_ALLOWLISTED`](#DYNAMIC_REQUIRE_NOT_ALLOWLISTED) | safety | Non-literal require |
39
+ | [`TS_SUPPRESSION_THRESHOLD_EXCEEDED`](#TS_SUPPRESSION_THRESHOLD_EXCEEDED) | safety | @ts-ignore / @ts-nocheck threshold |
40
+ | [`ANY_CAST_THRESHOLD_EXCEEDED`](#ANY_CAST_THRESHOLD_EXCEEDED) | safety | Explicit any cast threshold |
41
+ | [`IN_MEMORY_STORE_IN_PRODUCTION_SOURCE`](#IN_MEMORY_STORE_IN_PRODUCTION_SOURCE) | safety | In-memory store in production source |
42
+ | [`PEER_ISOLATION_DISABLED`](#PEER_ISOLATION_DISABLED) | safety | peerIsolation disabled on a rule |
43
+ | [`ARKRULE_STRUCTURE`](#ARKRULE_STRUCTURE) | arkrules | ArkRule structure sensor failed |
44
+ | [`ARKRULE_INVARIANT`](#ARKRULE_INVARIANT) | arkrules | ArkRule invariant failed |
45
+ | [`ARKRULE_SCOPE_EMPTY`](#ARKRULE_SCOPE_EMPTY) | arkrules | ArkRule appliesTo matched zero files |
46
+ | [`INVARIANT_UNCOVERED`](#INVARIANT_UNCOVERED) | arkrules | Invariant without coverage evidence |
47
+ | [`INVALID_CHANGE_PATH`](#INVALID_CHANGE_PATH) | preflight | Unsafe change path |
48
+ | [`DUPLICATE_CHANGE_PATH`](#DUPLICATE_CHANGE_PATH) | preflight | Duplicate path in change set |
49
+ | [`DELETE_TARGET_MISSING`](#DELETE_TARGET_MISSING) | preflight | Delete target missing |
50
+ | [`CHANGE_SET_EMPTY`](#CHANGE_SET_EMPTY) | preflight | Empty change set |
51
+ | [`FACTS_IDENTITY_MISMATCH`](#FACTS_IDENTITY_MISMATCH) | preflight | Base/candidate facts identity mismatch |
52
+ | [`CANDIDATE_DELETE_NOT_APPLIED`](#CANDIDATE_DELETE_NOT_APPLIED) | preflight | Candidate still contains deleted path |
53
+ | [`CANDIDATE_CHANGE_MISSING`](#CANDIDATE_CHANGE_MISSING) | preflight | Declared change missing from candidate |
54
+ | [`CANDIDATE_CONTENT_HASH_MISMATCH`](#CANDIDATE_CONTENT_HASH_MISMATCH) | preflight | Candidate content hash mismatch |
55
+ | [`UNDECLARED_CANDIDATE_CHANGE`](#UNDECLARED_CANDIDATE_CHANGE) | preflight | Undeclared candidate change |
56
+ | [`ATOMIC_PREFLIGHT_UNAVAILABLE`](#ATOMIC_PREFLIGHT_UNAVAILABLE) | preflight | Atomic preflight unavailable |
57
+ | [`DESIGN_SMELL_REGRESSION`](#DESIGN_SMELL_REGRESSION) | preflight | Design smell regression on base-relative ratchet |
58
+ | [`ANALYSIS_PARSE_INCOMPLETE`](#ANALYSIS_PARSE_INCOMPLETE) | analysis | Parse incomplete |
59
+ | [`ANALYSIS_HOST_UNAVAILABLE`](#ANALYSIS_HOST_UNAVAILABLE) | analysis | Analysis host unavailable |
60
+ | [`ADAPTER_NOT_ALLOWED_FOR_PORT`](#ADAPTER_NOT_ALLOWED_FOR_PORT) | adapter | Adapter not allowed for port |
61
+ | [`FORBIDDEN_PATTERN`](#FORBIDDEN_PATTERN) | snippet-policy | Forbidden regex pattern |
62
+ | [`FORBIDDEN_SUBSTRING`](#FORBIDDEN_SUBSTRING) | snippet-policy | Forbidden substring |
63
+ | [`FORBIDDEN_IMPORT`](#FORBIDDEN_IMPORT) | snippet-policy | Forbidden import target |
64
+ | [`POLICY_VIOLATION`](#POLICY_VIOLATION) | snippet-policy | Policy engine violation |
65
+ | [`EXTENSION_ERROR`](#EXTENSION_ERROR) | snippet-policy | AI gate extension error |
66
+ | [`AST_ANALYZER_ERROR`](#AST_ANALYZER_ERROR) | snippet-policy | AST analyzer error |
67
+ | [`CONFIG_INVALID_DYNAMIC_IMPORT_ALLOWLIST`](#CONFIG_INVALID_DYNAMIC_IMPORT_ALLOWLIST) | config | Invalid dynamicImportAllowlist |
68
+ | [`CONFIG_INVALID_SAFETY`](#CONFIG_INVALID_SAFETY) | config | Invalid safety object |
69
+ | [`CONFIG_INVALID_SAFETY_THRESHOLD`](#CONFIG_INVALID_SAFETY_THRESHOLD) | config | Invalid safety threshold |
70
+ | [`CONFIG_NO_LAYERS`](#CONFIG_NO_LAYERS) | config | No layers configured |
71
+ | [`CONFIG_LAYER_WITHOUT_NAME`](#CONFIG_LAYER_WITHOUT_NAME) | config | Layer missing name |
72
+ | [`CONFIG_INVALID_FORBIDDEN_GLOBALS`](#CONFIG_INVALID_FORBIDDEN_GLOBALS) | config | Invalid forbiddenGlobals |
73
+ | [`CONFIG_LAYER_WITHOUT_PATTERNS`](#CONFIG_LAYER_WITHOUT_PATTERNS) | config | Layer without patterns |
74
+ | [`CONFIG_INVALID_LAYER_PATTERN`](#CONFIG_INVALID_LAYER_PATTERN) | config | Invalid layer pattern |
75
+ | [`CONFIG_LAYER_PATTERN_NO_MATCHES`](#CONFIG_LAYER_PATTERN_NO_MATCHES) | config | Layer pattern matched no files |
76
+ | [`CONFIG_DUPLICATE_LAYER`](#CONFIG_DUPLICATE_LAYER) | config | Duplicate layer name |
77
+ | [`CONFIG_RULE_UNKNOWN_FROM_LAYER`](#CONFIG_RULE_UNKNOWN_FROM_LAYER) | config | Rule unknown from layer |
78
+ | [`CONFIG_RULE_UNKNOWN_TO_LAYER`](#CONFIG_RULE_UNKNOWN_TO_LAYER) | config | Rule unknown to layer |
79
+ | [`CONFIG_AMBIGUOUS_LAYERS`](#CONFIG_AMBIGUOUS_LAYERS) | config | Ambiguous layer classification |
80
+ | [`CONFIG_UNCLASSIFIED_FILES`](#CONFIG_UNCLASSIFIED_FILES) | config | Unclassified included files |
81
+ | [`ARK_UNKNOWN`](#ARK_UNKNOWN) | meta | Unknown diagnostic |
82
+
83
+ ## Layer and dependency graph
84
+
85
+ <a id="LAYER_IMPORT_VIOLATION"></a>
86
+
87
+ ### `LAYER_IMPORT_VIOLATION`
88
+
89
+ **Layer import not allowed**
90
+
91
+ - **Why:** A module import (or re-export) crosses a layer edge that ark.config.json does not allow. The architecture contract forbids that dependency direction so outer infrastructure cannot leak into pure or inner layers.
92
+ - **Fix:** Define a port in the source layer, inject the outer-layer implementation, or move/share the type with `import type` when the edge is type-only — then preflight again. Do not weaken the layer rule without a hash-bound policy acknowledgement.
93
+
94
+ <a id="LAYER_INTENT_REFERENCE_VIOLATION"></a>
95
+
96
+ ### `LAYER_INTENT_REFERENCE_VIOLATION`
97
+
98
+ **Intent referenced across a blocked layer edge**
99
+
100
+ - **Why:** A string intent (or intent-like reference) names a layer that the file’s layer may not reach under the contract rules — the same plane as import edges, for event/intent coupling.
101
+ - **Fix:** Reference that intent from a layer allowed to know about it (usually an adapter or application layer), or relocate the reference — then preflight again.
102
+
103
+ <a id="LAYER_REFERENCE_VIOLATION"></a>
104
+
105
+ ### `LAYER_REFERENCE_VIOLATION`
106
+
107
+ **Layer reference blocked (snippet / AI gate)**
108
+
109
+ - **Why:** Snippet analysis found an intent or string reference that would couple layers in a direction the architecture profile forbids.
110
+ - **Fix:** Move the reference to an allowed layer or introduce a port/event boundary, then re-run the snippet gate.
111
+
112
+ <a id="CIRCULAR_DEPENDENCY"></a>
113
+
114
+ ### `CIRCULAR_DEPENDENCY`
115
+
116
+ **Dependency cycle**
117
+
118
+ - **Why:** Two or more modules import each other in a loop. Cycles make ownership unclear and break stable layer direction.
119
+ - **Fix:** Extract the shared dependency into a third module, invert one edge behind a port, or merge units that are truly one — then preflight again.
120
+
121
+ ## Capabilities and ambient globals
122
+
123
+ <a id="FORBIDDEN_GLOBAL"></a>
124
+
125
+ ### `FORBIDDEN_GLOBAL`
126
+
127
+ **Forbidden ambient global or dual import**
128
+
129
+ - **Why:** The file’s layer lists this ambient (or its exact import dual, e.g. process / node:process) in forbiddenGlobals. Pure layers must not reach wall-clock, network, process, or similar effects directly.
130
+ - **Fix:** Inject the capability through a small port (Clock, HttpPort, Config, …), bind the implementation outside the walled layer, then preflight again.
131
+
132
+ <a id="CAPABILITY_VIOLATION"></a>
133
+
134
+ ### `CAPABILITY_VIOLATION`
135
+
136
+ **Denied effect capability**
137
+
138
+ - **Why:** The layer denies an effect capability (network, filesystem, clock, randomness, environment, process, persistence) and the candidate uses that effect via ambient or import evidence.
139
+ - **Fix:** Define a capability port in the walled layer, bind the implementation in an adapter layer, then preflight again. Never mechanical-safe — port shape is a design decision.
140
+
141
+ ## Publish and intents
142
+
143
+ <a id="RAW_EVENT_PUBLISH"></a>
144
+
145
+ ### `RAW_EVENT_PUBLISH`
146
+
147
+ **Raw event publish**
148
+
149
+ - **Why:** Publish went through a raw string or object instead of a registered intent creator, bypassing Ark intent contracts and tooling.
150
+ - **Fix:** Publish through a registered intent creator, then run Ark again.
151
+
152
+ <a id="PUBLISH_MISSING_SOURCE"></a>
153
+
154
+ ### `PUBLISH_MISSING_SOURCE`
155
+
156
+ **Publish missing metadata.source**
157
+
158
+ - **Why:** A strict Ark publish call omitted metadata.source, so the publishing layer cannot be verified.
159
+ - **Fix:** Add metadata.source to the publish call, then run Ark again.
160
+
161
+ <a id="PUBLISH_SOURCE_LAYER_MISMATCH"></a>
162
+
163
+ ### `PUBLISH_SOURCE_LAYER_MISMATCH`
164
+
165
+ **Publish source layer mismatch**
166
+
167
+ - **Why:** metadata.source resolves to a different layer than the file performing the publish.
168
+ - **Fix:** Use a source intent owned by the same layer as this file, or move the publish call to the owning layer.
169
+
170
+ <a id="UNKNOWN_INTENT"></a>
171
+
172
+ ### `UNKNOWN_INTENT`
173
+
174
+ **Unknown intent reference**
175
+
176
+ - **Why:** Snippet analysis saw an intent string that is not registered in the intent registry / profile under check.
177
+ - **Fix:** Register the intent or use a known intent name from the project registry, then re-run the gate.
178
+
179
+ ## Safety thresholds and dynamic loading
180
+
181
+ <a id="DYNAMIC_IMPORT_NOT_ALLOWLISTED"></a>
182
+
183
+ ### `DYNAMIC_IMPORT_NOT_ALLOWLISTED`
184
+
185
+ **Non-literal dynamic import**
186
+
187
+ - **Why:** A dynamic import(expr) cannot be resolved statically and the file is not on dynamicImportAllowlist. Unresolved dynamics can hide layer edges.
188
+ - **Fix:** Rewrite to a static import when possible, or add only reviewed files to dynamicImportAllowlist after human sign-off.
189
+
190
+ <a id="DYNAMIC_REQUIRE_NOT_ALLOWLISTED"></a>
191
+
192
+ ### `DYNAMIC_REQUIRE_NOT_ALLOWLISTED`
193
+
194
+ **Non-literal require**
195
+
196
+ - **Why:** A require(expr) cannot be resolved statically and is not allowlisted — same hide-the-edge risk as dynamic import.
197
+ - **Fix:** Prefer static import, or allowlist only reviewed files after sign-off.
198
+
199
+ <a id="TS_SUPPRESSION_THRESHOLD_EXCEEDED"></a>
200
+
201
+ ### `TS_SUPPRESSION_THRESHOLD_EXCEEDED`
202
+
203
+ **@ts-ignore / @ts-nocheck threshold**
204
+
205
+ - **Why:** Count of TypeScript suppressions in governed production source exceeds safety.maxTsSuppressions.
206
+ - **Fix:** Remove suppressions by fixing types, or raise the threshold only with an explicit production exception in ark.config.json.
207
+
208
+ <a id="ANY_CAST_THRESHOLD_EXCEEDED"></a>
209
+
210
+ ### `ANY_CAST_THRESHOLD_EXCEEDED`
211
+
212
+ **Explicit any cast threshold**
213
+
214
+ - **Why:** Count of explicit any casts exceeds safety.maxAnyCasts.
215
+ - **Fix:** Replace any with precise types, or raise the threshold only with a documented exception.
216
+
217
+ <a id="IN_MEMORY_STORE_IN_PRODUCTION_SOURCE"></a>
218
+
219
+ ### `IN_MEMORY_STORE_IN_PRODUCTION_SOURCE`
220
+
221
+ **In-memory store in production source**
222
+
223
+ - **Why:** Governed production source references an Ark InMemory* store without safety.allowInMemory — durable systems should not ship ephemeral stores by accident.
224
+ - **Fix:** Provide a durable store implementation, or set safety.allowInMemory only for an explicitly ephemeral service.
225
+
226
+ <a id="PEER_ISOLATION_DISABLED"></a>
227
+
228
+ ### `PEER_ISOLATION_DISABLED`
229
+
230
+ **peerIsolation disabled on a rule**
231
+
232
+ - **Why:** A same-layer or peer rule disables peerIsolation (or omits it where required), which allows cross-slice coupling the contract otherwise blocks.
233
+ - **Fix:** Restore peerIsolation: true, or set safety.allowDisabledPeerIsolation only with a documented production exception.
234
+
235
+ ## ArkRules (structure and invariants)
236
+
237
+ <a id="ARKRULE_STRUCTURE"></a>
238
+
239
+ ### `ARKRULE_STRUCTURE`
240
+
241
+ **ArkRule structure sensor failed**
242
+
243
+ - **Why:** An opt-in ArkRules structure sensor (private state, factory shape, event publish, …) failed on a governed file for a declared arkruleId.
244
+ - **Fix:** Restore the declared structure for the ArkRule (see arkruleSource), then preflight again. Do not demote the rule without a hash-bound policy acknowledgement.
245
+
246
+ <a id="ARKRULE_INVARIANT"></a>
247
+
248
+ ### `ARKRULE_INVARIANT`
249
+
250
+ **ArkRule invariant failed**
251
+
252
+ - **Why:** Reserved / remediation-recognized code for invariant-plane failures bound to an ArkRule id (coverage path also emits INVARIANT_UNCOVERED).
253
+ - **Fix:** Fix the invariant for the ArkRule declared in arkrules/<Layer>.json, then preflight again. Do not demote without acknowledgement.
254
+
255
+ <a id="ARKRULE_SCOPE_EMPTY"></a>
256
+
257
+ ### `ARKRULE_SCOPE_EMPTY`
258
+
259
+ **ArkRule appliesTo matched zero files** · often advisory
260
+
261
+ - **Why:** An ArkRule’s appliesTo globs matched no governed files — the rule cannot observe what it claims to protect.
262
+ - **Fix:** Fix appliesTo globs so they match governed files, or remove the rule. Enforced empty scope fails; advisory empty scope warns.
263
+
264
+ <a id="INVARIANT_UNCOVERED"></a>
265
+
266
+ ### `INVARIANT_UNCOVERED`
267
+
268
+ **Invariant without coverage evidence**
269
+
270
+ - **Why:** An ArkRules invariant is under contract but no covering test title or declared symbol evidence was found (or coverage is partial).
271
+ - **Fix:** Add a test title or declared symbol covering the arkruleId, then preflight again. Missing test globs report partial — never fake green.
272
+
273
+ ## Atomic preflight and change sets
274
+
275
+ <a id="INVALID_CHANGE_PATH"></a>
276
+
277
+ ### `INVALID_CHANGE_PATH`
278
+
279
+ **Unsafe change path**
280
+
281
+ - **Why:** A change set entry is not a safe, non-empty project-relative path (absolute, escape, empty, or NUL).
282
+ - **Fix:** Use canonical project-relative paths only in the atomic change set, then preflight again.
283
+
284
+ <a id="DUPLICATE_CHANGE_PATH"></a>
285
+
286
+ ### `DUPLICATE_CHANGE_PATH`
287
+
288
+ **Duplicate path in change set**
289
+
290
+ - **Why:** The atomic change set lists more than one operation for the same path.
291
+ - **Fix:** Collapse to one create/update/delete per path, then preflight again.
292
+
293
+ <a id="DELETE_TARGET_MISSING"></a>
294
+
295
+ ### `DELETE_TARGET_MISSING`
296
+
297
+ **Delete target missing**
298
+
299
+ - **Why:** A delete operation targets a path that is not present in the supplied base tree.
300
+ - **Fix:** Remove the delete, or include the file in the base tree facts, then preflight again.
301
+
302
+ <a id="CHANGE_SET_EMPTY"></a>
303
+
304
+ ### `CHANGE_SET_EMPTY`
305
+
306
+ **Empty change set**
307
+
308
+ - **Why:** Atomic preflight was invoked with no create, update, or delete operations.
309
+ - **Fix:** Provide at least one change operation, then preflight again.
310
+
311
+ <a id="FACTS_IDENTITY_MISMATCH"></a>
312
+
313
+ ### `FACTS_IDENTITY_MISMATCH`
314
+
315
+ **Base/candidate facts identity mismatch**
316
+
317
+ - **Why:** Base and candidate resolved facts disagree on resolver, compiler, evidence requirements, or package identity — verdicts would not be comparable.
318
+ - **Fix:** Regenerate both fact snapshots with the same resolver/compiler/evidence requirements, then preflight again.
319
+
320
+ <a id="CANDIDATE_DELETE_NOT_APPLIED"></a>
321
+
322
+ ### `CANDIDATE_DELETE_NOT_APPLIED`
323
+
324
+ **Candidate still contains deleted path**
325
+
326
+ - **Why:** Facts claim a delete, but the candidate tree still includes the path.
327
+ - **Fix:** Ensure the candidate facts apply the delete (path absent), then preflight again.
328
+
329
+ <a id="CANDIDATE_CHANGE_MISSING"></a>
330
+
331
+ ### `CANDIDATE_CHANGE_MISSING`
332
+
333
+ **Declared change missing from candidate**
334
+
335
+ - **Why:** The change set declares a create/update whose path is missing from candidate facts.
336
+ - **Fix:** Include the new content in the candidate facts (or drop the operation), then preflight again.
337
+
338
+ <a id="CANDIDATE_CONTENT_HASH_MISMATCH"></a>
339
+
340
+ ### `CANDIDATE_CONTENT_HASH_MISMATCH`
341
+
342
+ **Candidate content hash mismatch**
343
+
344
+ - **Why:** The candidate file content hash does not match the hash expected for the declared change.
345
+ - **Fix:** Rebuild candidate facts from the exact proposed content, then preflight again.
346
+
347
+ <a id="UNDECLARED_CANDIDATE_CHANGE"></a>
348
+
349
+ ### `UNDECLARED_CANDIDATE_CHANGE`
350
+
351
+ **Undeclared candidate change**
352
+
353
+ - **Why:** Candidate facts differ from base for a path that was not listed in the explicit change set.
354
+ - **Fix:** Declare every path that changes in the atomic change set, then preflight again.
355
+
356
+ <a id="ATOMIC_PREFLIGHT_UNAVAILABLE"></a>
357
+
358
+ ### `ATOMIC_PREFLIGHT_UNAVAILABLE`
359
+
360
+ **Atomic preflight unavailable**
361
+
362
+ - **Why:** The host/MCP path could not run the atomic preflight engine (missing facts, incomplete setup, or unsupported mode).
363
+ - **Fix:** Use resolved-candidate facts / ark_prepare_change with a complete batch, or fall back to ark-check on disk. Do not treat missing preflight as green.
364
+
365
+ <a id="DESIGN_SMELL_REGRESSION"></a>
366
+
367
+ ### `DESIGN_SMELL_REGRESSION`
368
+
369
+ **Design smell regression on base-relative ratchet**
370
+
371
+ - **Why:** Compared to the base ref, the candidate introduces or worsens a blocking design-smell class (e.g. domain-logic-in-ui) under --fail-on-new-smells.
372
+ - **Fix:** Revert the regression or redesign so the smell does not worsen versus base, then re-run with the same base ref.
373
+
374
+ ## Analysis host and completeness
375
+
376
+ <a id="ANALYSIS_PARSE_INCOMPLETE"></a>
377
+
378
+ ### `ANALYSIS_PARSE_INCOMPLETE`
379
+
380
+ **Parse incomplete**
381
+
382
+ - **Why:** Governed source could not be fully parsed; analysis is partial and must not paint green.
383
+ - **Fix:** Fix syntax/parse errors in governed files (or restore a usable TypeScript host), then re-run. Partial never means pass.
384
+
385
+ <a id="ANALYSIS_HOST_UNAVAILABLE"></a>
386
+
387
+ ### `ANALYSIS_HOST_UNAVAILABLE`
388
+
389
+ **Analysis host unavailable**
390
+
391
+ - **Why:** No usable TypeScript / analysis host was available for this invocation.
392
+ - **Fix:** Install a supported TypeScript version visible to the project, then re-run. Unavailable analysis is fail-closed.
393
+
394
+ ## Port adapters
395
+
396
+ <a id="ADAPTER_NOT_ALLOWED_FOR_PORT"></a>
397
+
398
+ ### `ADAPTER_NOT_ALLOWED_FOR_PORT`
399
+
400
+ **Adapter not allowed for port**
401
+
402
+ - **Why:** Runtime/port wiring selected an adapter implementation that the architecture profile does not allow for that port.
403
+ - **Fix:** Bind an allowed adapter for the port, or adjust the profile with an explicit policy decision — then re-run.
404
+
405
+ ## Snippet / AICodeGate policy
406
+
407
+ <a id="FORBIDDEN_PATTERN"></a>
408
+
409
+ ### `FORBIDDEN_PATTERN`
410
+
411
+ **Forbidden regex pattern**
412
+
413
+ - **Why:** Snippet content matched a project or profile forbiddenPatterns rule.
414
+ - **Fix:** Remove or rewrite the matching code so the pattern no longer matches, then re-run the snippet gate.
415
+
416
+ <a id="FORBIDDEN_SUBSTRING"></a>
417
+
418
+ ### `FORBIDDEN_SUBSTRING`
419
+
420
+ **Forbidden substring**
421
+
422
+ - **Why:** Snippet content contained a forbidden substring from the AI gate options/profile.
423
+ - **Fix:** Remove the forbidden substring, then re-run the snippet gate.
424
+
425
+ <a id="FORBIDDEN_IMPORT"></a>
426
+
427
+ ### `FORBIDDEN_IMPORT`
428
+
429
+ **Forbidden import target**
430
+
431
+ - **Why:** Snippet imported or required a module listed as forbidden for the active profile.
432
+ - **Fix:** Import an allowed module or inject the dependency behind a port, then re-run.
433
+
434
+ <a id="POLICY_VIOLATION"></a>
435
+
436
+ ### `POLICY_VIOLATION`
437
+
438
+ **Policy engine violation**
439
+
440
+ - **Why:** A registered Policy failed on the snippet or generated code under evaluation.
441
+ - **Fix:** Adjust the code to satisfy the named policy, or change the policy only through an explicit contract decision.
442
+
443
+ <a id="EXTENSION_ERROR"></a>
444
+
445
+ ### `EXTENSION_ERROR`
446
+
447
+ **AI gate extension error**
448
+
449
+ - **Why:** A registered AICodeGate extension threw while analyzing the snippet.
450
+ - **Fix:** Fix or remove the failing extension; do not ignore extension failures as pass.
451
+
452
+ <a id="AST_ANALYZER_ERROR"></a>
453
+
454
+ ### `AST_ANALYZER_ERROR`
455
+
456
+ **AST analyzer error**
457
+
458
+ - **Why:** Built-in AST/symbol analysis failed (host error or unexpected analyzer exception).
459
+ - **Fix:** Ensure TypeScript host and snippet are valid; re-run. If the analyzer crashes on valid input, file a bug with a minimal fixture.
460
+
461
+ ## Configuration diagnostics
462
+
463
+ <a id="CONFIG_INVALID_DYNAMIC_IMPORT_ALLOWLIST"></a>
464
+
465
+ ### `CONFIG_INVALID_DYNAMIC_IMPORT_ALLOWLIST`
466
+
467
+ **Invalid dynamicImportAllowlist** · often advisory
468
+
469
+ - **Why:** dynamicImportAllowlist is present but not an array of file globs.
470
+ - **Fix:** Set dynamicImportAllowlist to an array of project-relative globs (or omit it).
471
+
472
+ <a id="CONFIG_INVALID_SAFETY"></a>
473
+
474
+ ### `CONFIG_INVALID_SAFETY`
475
+
476
+ **Invalid safety object** · often advisory
477
+
478
+ - **Why:** The safety field is present but not an object.
479
+ - **Fix:** Use a safety object with optional maxTsSuppressions, maxAnyCasts, allowInMemory, allowDisabledPeerIsolation.
480
+
481
+ <a id="CONFIG_INVALID_SAFETY_THRESHOLD"></a>
482
+
483
+ ### `CONFIG_INVALID_SAFETY_THRESHOLD`
484
+
485
+ **Invalid safety threshold** · often advisory
486
+
487
+ - **Why:** A safety threshold (maxTsSuppressions / maxAnyCasts) is not a non-negative integer.
488
+ - **Fix:** Set each threshold to a non-negative integer.
489
+
490
+ <a id="CONFIG_NO_LAYERS"></a>
491
+
492
+ ### `CONFIG_NO_LAYERS`
493
+
494
+ **No layers configured** · often advisory
495
+
496
+ - **Why:** ark.config.json has no file layers, so import-boundary enforcement cannot classify files.
497
+ - **Fix:** Declare at least one layer with name + patterns (or run ark start / a preset).
498
+
499
+ <a id="CONFIG_LAYER_WITHOUT_NAME"></a>
500
+
501
+ ### `CONFIG_LAYER_WITHOUT_NAME`
502
+
503
+ **Layer missing name** · often advisory
504
+
505
+ - **Why:** A configured layer entry has no name.
506
+ - **Fix:** Give every layer a unique non-empty name.
507
+
508
+ <a id="CONFIG_INVALID_FORBIDDEN_GLOBALS"></a>
509
+
510
+ ### `CONFIG_INVALID_FORBIDDEN_GLOBALS`
511
+
512
+ **Invalid forbiddenGlobals** · often advisory
513
+
514
+ - **Why:** A layer’s forbiddenGlobals is not an array of strings; the entry is ignored.
515
+ - **Fix:** Use an array of strings (e.g. ["fetch", "Date.now"]).
516
+
517
+ <a id="CONFIG_LAYER_WITHOUT_PATTERNS"></a>
518
+
519
+ ### `CONFIG_LAYER_WITHOUT_PATTERNS`
520
+
521
+ **Layer without patterns** · often advisory
522
+
523
+ - **Why:** A named layer has no file patterns and will never classify files.
524
+ - **Fix:** Add patterns globs that match the layer’s source tree.
525
+
526
+ <a id="CONFIG_INVALID_LAYER_PATTERN"></a>
527
+
528
+ ### `CONFIG_INVALID_LAYER_PATTERN`
529
+
530
+ **Invalid layer pattern** · often advisory
531
+
532
+ - **Why:** A layer pattern is not a valid glob / failed to compile.
533
+ - **Fix:** Fix the pattern syntax for that layer.
534
+
535
+ <a id="CONFIG_LAYER_PATTERN_NO_MATCHES"></a>
536
+
537
+ ### `CONFIG_LAYER_PATTERN_NO_MATCHES`
538
+
539
+ **Layer pattern matched no files** · often advisory
540
+
541
+ - **Why:** A layer pattern matched zero included files (often a typo or include mismatch).
542
+ - **Fix:** Adjust the pattern or include roots so governed files match.
543
+
544
+ <a id="CONFIG_DUPLICATE_LAYER"></a>
545
+
546
+ ### `CONFIG_DUPLICATE_LAYER`
547
+
548
+ **Duplicate layer name** · often advisory
549
+
550
+ - **Why:** The same layer name appears more than once in configuration.
551
+ - **Fix:** Rename or merge duplicate layer entries.
552
+
553
+ <a id="CONFIG_RULE_UNKNOWN_FROM_LAYER"></a>
554
+
555
+ ### `CONFIG_RULE_UNKNOWN_FROM_LAYER`
556
+
557
+ **Rule unknown from layer** · often advisory
558
+
559
+ - **Why:** A dependency rule references a source layer name that is not declared.
560
+ - **Fix:** Fix the rule’s from field to a declared layer name.
561
+
562
+ <a id="CONFIG_RULE_UNKNOWN_TO_LAYER"></a>
563
+
564
+ ### `CONFIG_RULE_UNKNOWN_TO_LAYER`
565
+
566
+ **Rule unknown to layer** · often advisory
567
+
568
+ - **Why:** A dependency rule references a target layer name that is not declared.
569
+ - **Fix:** Fix the rule’s to field to a declared layer name.
570
+
571
+ <a id="CONFIG_AMBIGUOUS_LAYERS"></a>
572
+
573
+ ### `CONFIG_AMBIGUOUS_LAYERS`
574
+
575
+ **Ambiguous layer classification** · often advisory
576
+
577
+ - **Why:** Some files match multiple layers at equal specificity; classification falls back to declaration order.
578
+ - **Fix:** Disambiguate overlapping patterns so each file has one clear layer owner.
579
+
580
+ <a id="CONFIG_UNCLASSIFIED_FILES"></a>
581
+
582
+ ### `CONFIG_UNCLASSIFIED_FILES`
583
+
584
+ **Unclassified included files** · often advisory
585
+
586
+ - **Why:** Included source files match no layer pattern; import rules will not enforce on them.
587
+ - **Fix:** Extend layer patterns or narrow include so every governed file is classified.
588
+
589
+ ## Meta
590
+
591
+ <a id="ARK_UNKNOWN"></a>
592
+
593
+ ### `ARK_UNKNOWN`
594
+
595
+ **Unknown diagnostic**
596
+
597
+ - **Why:** A diagnostic lacked a stable ruleId/code; adapters may emit this fallback so agents never see an empty id.
598
+ - **Fix:** Resolve the underlying finding without weakening ark.config.json, then run Ark again. Prefer fixing the producer to emit a catalogued ruleId.
599
+
600
+ ## Related
601
+
602
+ - [Agent guide](agent-guide.md) — CLI / MCP / skills
603
+ - [Configuration](configuration.md) — ark.config.json
604
+ - [Package surface](package-surface.md) — stable exports
605
+ - [Product voice](product-voice.md) — guardrail catalog language
606
+ - [AI gates](ai-gates.md) — host install and scanner envelope