Layer policy
The six-layer package graph (core → substrates → shared libraries/adapters → tools → check/adapter packs → cli) is enforced by dependency-cruiser. Build fails on any forbidden edge. This doc walks every rule and the reasoning.
For the conceptual layer narrative, see ../10-concepts/03-modular-monolith.md.
The literal rules are at .config/dependency-cruiser.cjs.
Error and resiliency ownership
Failure semantics follow the same layer cake (ADR-0181 / ADR-0183). Do not invert these arrows:
| Layer | Owns | Must not own |
|---|---|---|
| core | ErrorDefinition, catalogs (defineErrorCatalog), ToolError / createToolError, total normalizeFailure + projections, toSafeDiagnosticData, withRetry / cancel+deadline constructors, worker failure-wire shapes | Terminal rendering, process exit, SIGINT listeners, contracts exit numbers |
| contracts | EXIT_CODES (including CANCELLED = 130), CommandOutcome error slots, suggestion helpers | Definition catalogs, envelope construction, retry loops |
| cli | Effectful reportFailure fan-out, last-resort process net, interrupt→AbortSignal coordinator, run-plane runOutcome stamping | Package-owned public codes (tools own those) |
| tools / substrates | Package-owned error catalogs (extensionPoints.errorCatalog), throw/report sites | Process-global registries, host presentation encoding |
Core still imports nothing from contracts or cli. Catalog aggregation is per-invocation (registry), never a module-singleton map. Details: Error and resiliency model.
Generic hygiene rules
Three rules unrelated to the layer architecture but enforced workspace-wide.
no-circular
{ name: 'no-circular', from: {}, to: { circular: true } }
No circular dependencies between modules within a package. The main pass ignores type-only edges (tsPreCompilationDeps: false) so it flags only runtime cycles; the type-aware pass (.config/dependency-cruiser.types.cjs) re-runs no-circular over the type-inclusive graph, so type-only cycles are caught too. A circular dep — runtime or type-only — is a structural smell, usually meaning a type or constant belongs in a third file.
no-deprecated-core
{
from: {},
to: {
dependencyTypes: ['core'],
path: ['^(punycode|domain|constants|sys|_linklist|_stream_wrap)