feat(install): monorepo arch boundaries + R3 inertness alarm — GH #534 - #539
Merged
Conversation
…#534 After #508 made arch:check RUN on a monorepo, the shipped .dependency-cruiser.cjs still carried only layered-monolith rules (src/domain|application|infrastructure| features). For a pnpm monorepo the boundaries that matter — packages/* ↛ apps/* and apps ↔ apps — were absent, so arch:check passed green while those imports were unguarded; and unlike R2 (check:globs) there was NO inertness detector, so the gap was silent. Two parts: 1. Add layout-agnostic boundary rules to the shipped arch config: no-package-to-app (packages↛apps, error) and no-cross-app (apps↔apps, warn). Both key on (?:^|/) packages/ and (?:^|/)apps/ → INERT on a flat/layered single project, ACTIVE on a monorepo. No install-time layout detection needed. 2. check:arch-boundaries (scripts/check-arch-boundaries.sh) — the R3 inertness alarm, the dependency-cruiser analog of check:globs. On an apps/+packages/ monorepo it FAILS when the arch config has no packages↛apps rule (e.g. a pre-existing config install did not overwrite). Dependency-free bash; skips on flat / single-tree workspace. dependency-cruiser has no built-in "rule matched nothing" report (DeepWiki sverweij/dependency-cruiser 2026-06-15), so this is BUILD, the R3 analog of the own-built check-rule-globs.sh. Wiring: ship + chmod the detector; add check:arch-boundaries script + into validate; add to the CI-orphan gate-map; add a step to both shipped CI templates after arch:check. Regression: tests/install-sh/gh-534-arch-boundaries.test.sh — config carries the rules + valid JS; behavioral regex reaches the #534 repro path (inert on flat); detector Arm A (has rule → PASS) / Arm B paired-neg (no rule → FAIL) / Arm C (flat → skip). install-sh suite 31/31, principles 188/188. Prior-art: prior-art-evaluations.md#119 (BUILD — no upstream: dependency-cruiser has no inert-rule report per DeepWiki+WebSearch 2026-06-15; R3 analog of the own-built check-rule-globs.sh, same family as #114/#115. Boundary rules themselves are plain dependency-cruiser config = REUSE of its engine; only the detector is BUILD.)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #534
Problem
After #508 made
arch:checkrun on a monorepo, the shipped.dependency-cruiser.cjsstill carried only layered-monolith rules (src/domain|application|infrastructure|features). For a pnpm monorepo the boundaries that matter —packages/* ↛ apps/*andapps ↔ apps— were absent, soarch:checkpassed green while those imports were unguarded. And unlike R2 (which has the loudcheck:globsinertness alarm), R3 had no detector — the inertness was silent.Fix (two parts)
no-package-to-app(packages↛apps, error) andno-cross-app(apps↔apps, warn). Both key on(?:^|/)packages//(?:^|/)apps/→ inert on a flat / layered single project, active on a monorepo. No install-time layout detection needed; no risk of false-positives on non-monorepos.check:arch-boundaries(scripts/check-arch-boundaries.sh) — the R3 inertness alarm, the dependency-cruiser analog ofcheck:globs. On anapps/+packages/monorepo it FAILS when the arch config has nopackages↛appsrule (e.g. a pre-existing config install didn't overwrite). Dependency-free bash; skips on flat / single-tree workspace.Wiring: ship + chmod the detector; add
check:arch-boundariesscript + intovalidate; add to the CI-orphan gate-map; add a step to both shipped CI templates afterarch:check.Verification
tests/install-sh/gh-534-arch-boundaries.test.sh: config carries the rules + valid JS; behavioral regex reaches the #534 repro path (inert on flat); detector Arm A (has rule → PASS) / Arm B paired-neg (no rule → FAIL) / Arm C (flat → skip). End-to-end real install wires + ships + the detector passes. install-sh suite 31/31, principles 188/188.Build-vs-reuse
BUILD (SSOT #119): DeepWiki
sverweij/dependency-cruiser(2026-06-15) confirms it has no built-in "rule matched zero modules" report, so there's nothing to ADOPT — this is the R3 analog of the own-builtcheck-rule-globs.sh(same family as #114/#115). The boundary rules are plain dependency-cruiser config (REUSE of its engine); only the detector is BUILD.§1.7 Forward-check applied
Complies with active disciplines, verified against source: no-paid-llm-in-ci — the detector is dependency-free bash, no node/depcruise/LLM at runtime (
packages/core/audit-self/check-arch-boundaries.sh:13); build-first-reuse-default §3 — BUILD verdict justified by the DeepWiki+WebSearch negative-existence sweep recorded as SSOT #119 atdocs/meta-factory/prior-art-evaluations.md:190, and the boundary rules are REUSE of dependency-cruiser's own engine (config-only); capability-commit gate —Prior-art:trailer cites #119, landed in this same commit (§1.9 existence-check passes); doc-authority — new.sh/.cjsare code (no prose header), the SSOT row keeps the 8-column register format; non-duplicative wiring into thevalidatechain atinstall.sh:877.§1.7 Backward-check applied
Swept all surfaces under the new gate's scope (R3 architecture-boundary enforcement): modelled the detector and its messaging on the existing R2 sibling
packages/core/audit-self/check-rule-globs.sh:5(the "silently inert" alarm), so R2 and R3 now have parallel liveness gates. The boundary rules were added to the single shipped arch config attemplates/ts-server/dependency-cruiser.cjs:145(shipped to both stacks). Wired the detector into every surface that already referencesarch:check— thevalidatechain, the CI-orphan gate-map, and both shipped CI templates (templates/ts-server/github-actions-ci.yml:80+ the react-next ui template). Regression coverage with a paired-negative intests/install-sh/gh-534-arch-boundaries.test.sh:50. Verified no existing install-sh test asserts an exclusive gate list (full suite 31/31); the detector skips cleanly on flat/single-tree layouts so existing non-monorepo consumers keep passing.