prometeu-studio/discussion/lessons/DSC-0064-multi-frontend-architectural-tests/LSN-0066-archunit-guards-java-multi-frontend-boundaries.md
bQUARKz e809ce63d3
All checks were successful
JaCoCo Coverage #### Project Overview No changes detected, that affect the code coverage. * Line Coverage: 62.10% (17811/28682) * Branch Coverage: 52.81% (6878/13025) * Lines of Code: 28682 * Cyclomatic Complexity: 11494 #### Quality Gates Summary Output truncated.
Test / Build skipped: 15, passed: 654
Intrepid/Prometeu/Studio/pipeline/head This commit looks good
Intrepid/Prometeu/Studio/pipeline/pr-master This commit looks good
implements PLN-0129
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.
2026-09-19 03:32:43 +01:00

6.3 KiB

id ticket title created tags
LSN-0066 multi-frontend-architectural-tests ArchUnit guards Java multi-frontend boundaries 2026-09-19
compiler
compiler-general
studio
frontend
architecture
tests
multi-frontend

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.pbs
  • new 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. Package p.studio.compiler.pbs is not the complete boundary. Name prefixes PBS* / Pbs* are not the identity.
  • Production may depend on PBS types only in:
    • the PBS module itself;
    • prometeu-frontend-registry / FrontendRegistryService, and only on PBSFrontendProvider and PBSDefinitions.
  • AppContainer is not a PBS composition root. It may call FrontendRegistryService.bootstrapDefaults(). It must not instantiate PBS types.
  • synth is not in the production allowlist and must not be registered in bootstrapDefaults().
  • Runtime, PVM, and the Rust repository stay out of this discussion (LSN-0061).
  • IRBackendExecutableContractTest remains 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:

  1. classes outside the PBS module and the registry must not depend on PBS-module types;
  2. registry production may depend only on PBSFrontendProvider and PBSDefinitions from that module;
  3. frontend-api p.studio.compiler.models must 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-registry as implementation/api;
  • :prometeu-architecture-tests as testImplementation (needed to classify class origin).

The __pbs. source scan moved to CommonBackendPbsPrefixScanTest and still covers backend/, lifecycle/, and workspaces/stages/.

Gradle graph cleanup:

  • prometeu-app and prometeu-lsp-v1 no longer implementation PBS. Runtime classloading of PBSFrontendProvider still comes through the registry's implementation dependency.
  • prometeu-studio no longer testImplementation PBS. 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() constructs PBSFrontendProvider. That is the allowed composition root.
  • App calls FrontendRegistryService.bootstrapDefaults() and has no PBS project dependency.

Bad:

  • Searching source for import p.studio.compiler.pbs and calling the boundary protected.
  • Treating AppContainer as the place that may new PBSFrontendProvider().
  • Identifying PBS by class name prefix, so a future PbsLike helper in common code is banned or a PBS facade is missed.
  • Adding ArchUnit to java-common-conventions for every module.

Pitfalls

  • Same Java package does not mean same Gradle module. FrontendRegistryService and PBSFrontendProvider both sit in p.studio.compiler. Origin is the module path or JAR name.
  • @AnalyzeClasses classes must not mix @ArchTest and Jupiter @Test on the same class. The ArchUnit engine owns @ArchTest.
  • DoNotIncludeTests is 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.
  • testImplementation of 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.md
  • docs/specs/compiler/20. IRBackend to IRVM Lowering Specification.md
  • docs/specs/compiler/22. Backend Spec-to-Test Conformance Matrix.md
  • prometeu-architecture-tests/src/test/java/p/studio/architecture/PbsModuleBoundaryArchTest.java
  • prometeu-architecture-tests/src/test/java/p/studio/architecture/PbsGradleDependencyAllowlistTest.java
  • prometeu-compiler/prometeu-frontend-registry/src/main/java/p/studio/compiler/FrontendRegistryService.java
  • prometeu-compiler/prometeu-frontend-api/src/test/java/p/studio/compiler/models/IRBackendExecutableContractTest.java