Add ArchUnit guards for Java multi-frontend boundaries in a test-only module. Identify PBS by frontend-module origin, allow only the registry as composition root, and lock the wording in specs 19, 20, and 22. Housekeep DSC-0064 with LSN-0066.
6.3 KiB
| id | ticket | title | created | tags | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| LSN-0066 | multi-frontend-architectural-tests | ArchUnit guards Java multi-frontend boundaries | 2026-09-19 |
|
ArchUnit guards Java multi-frontend boundaries
Original Problem
The multi-frontend boundaries already existed in specs and lessons: common
code selects a frontend by languageId, IRBackend is language-neutral,
lifecycle assembly is common, and PBS is one provider. The automated
protection did not match that model.
The old guards walked Java source and searched for substrings:
import p.studio.compiler.pbsnew PBSFrontendPhaseService(new PbsEditorialSupportService(
Those checks missed field, signature, and constructor coupling. They also
treated p.studio.compiler.pbs as the whole PBS surface. Facades such as
PBSFrontendProvider, PBSDefinitions, and PBSFrontendPhaseService live
in the PBS module but not in that package. prometeu-app and
prometeu-lsp-v1 declared an implementation dependency on PBS without
importing any PBS type.
Consolidated Decision
Java multi-frontend boundaries are enforced by ArchUnit + JUnit 5, not by
source substring search, except for the __pbs. literal scan that bytecode
cannot see.
Durable locks from DEC-0050:
- ArchUnit is test-only, pinned in
gradle/libs.versions.toml. - Rules live in the test-only Gradle project
:prometeu-architecture-tests. That project has no production sources. It is not a plugin loader. - A PBS type is a class whose bytecode originates from
:prometeu-compiler:frontends:prometeu-frontend-pbs. Packagep.studio.compiler.pbsis not the complete boundary. Name prefixesPBS*/Pbs*are not the identity. - Production may depend on PBS types only in:
- the PBS module itself;
prometeu-frontend-registry/FrontendRegistryService, and only onPBSFrontendProviderandPBSDefinitions.
AppContaineris not a PBS composition root. It may callFrontendRegistryService.bootstrapDefaults(). It must not instantiate PBS types.synthis not in the production allowlist and must not be registered inbootstrapDefaults().- Runtime, PVM, and the Rust repository stay out of this discussion (LSN-0061).
IRBackendExecutableContractTestremains the public-contract shape audit. ArchUnit covers module-origin dependence.
Do not migrate PBS facades into another package just to make the test
easier. Do not ban the word PBS in docs, fixtures, or comments.
Final Implementation
:prometeu-architecture-tests imports production classes under p.studio
with ImportOption.DoNotIncludeTests and applies three ArchUnit rules:
- classes outside the PBS module and the registry must not depend on PBS-module types;
- registry production may depend only on
PBSFrontendProviderandPBSDefinitionsfrom that module; - frontend-api
p.studio.compiler.modelsmust not depend on PBS-module types.
A separate JUnit test walks build.gradle.kts files and allows the PBS
project dependency only for:
:prometeu-compiler:prometeu-frontend-registryasimplementation/api;:prometeu-architecture-testsastestImplementation(needed to classify class origin).
The __pbs. source scan moved to
CommonBackendPbsPrefixScanTest and still covers backend/, lifecycle/,
and workspaces/stages/.
Gradle graph cleanup:
prometeu-appandprometeu-lsp-v1no longerimplementationPBS. Runtime classloading ofPBSFrontendProviderstill comes through the registry's implementation dependency.prometeu-studiono longertestImplementationPBS. No studio test compiled against PBS types.
Source-walk import/constructor tests were deleted.
FrontendProviderBoundaryTest keeps only
compileOnlyFrontendProviderMayOmitLanguageService.
Specs 19 §11 and 20 now say common/platform code must not depend on types
from the PBS frontend module. Matrix rows G19-11.6, G20-4.1.2, and G20-4.3.3
point at the ArchUnit rules and the __pbs. scan.
Examples
Good:
- ArchUnit failure names the class that depends on a PBS-module type,
including a facade in package
p.studio.compiler. - Registry
bootstrapDefaults()constructsPBSFrontendProvider. That is the allowed composition root. - App calls
FrontendRegistryService.bootstrapDefaults()and has no PBS project dependency.
Bad:
- Searching source for
import p.studio.compiler.pbsand calling the boundary protected. - Treating
AppContaineras the place that maynew PBSFrontendProvider(). - Identifying PBS by class name prefix, so a future
PbsLikehelper in common code is banned or a PBS facade is missed. - Adding ArchUnit to
java-common-conventionsfor every module.
Pitfalls
- Same Java package does not mean same Gradle module.
FrontendRegistryServiceandPBSFrontendProviderboth sit inp.studio.compiler. Origin is the module path or JAR name. @AnalyzeClassesclasses must not mix@ArchTestand Jupiter@Teston the same class. The ArchUnit engine owns@ArchTest.DoNotIncludeTestsis required. The architecture-test sources themselves reference PBS types in order to name the allowlist.- Removing PBS from app/lsp compile classpath is safe only because registry
still
implementations PBS, which is runtime-transitive. testImplementationof PBS on studio is not a production leak, but if no studio test needs PBS types it is still a lying graph. The allowlist test rejects it.- Do not point ArchUnit at the Rust runtime.
__pbs.in Java source is a string contract, not a type dependency.
References
- Decision:
DEC-0050 - Plan:
PLN-0129 - Related lessons:
LSN-0055,LSN-0059,LSN-0062,LSN-0063,LSN-0061,LSN-0065 docs/specs/compiler/19. Verification and Safety Checks Specification.mddocs/specs/compiler/20. IRBackend to IRVM Lowering Specification.mddocs/specs/compiler/22. Backend Spec-to-Test Conformance Matrix.mdprometeu-architecture-tests/src/test/java/p/studio/architecture/PbsModuleBoundaryArchTest.javaprometeu-architecture-tests/src/test/java/p/studio/architecture/PbsGradleDependencyAllowlistTest.javaprometeu-compiler/prometeu-frontend-registry/src/main/java/p/studio/compiler/FrontendRegistryService.javaprometeu-compiler/prometeu-frontend-api/src/test/java/p/studio/compiler/models/IRBackendExecutableContractTest.java