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
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.
152 lines
6.3 KiB
Markdown
152 lines
6.3 KiB
Markdown
---
|
|
id: LSN-0066
|
|
ticket: multi-frontend-architectural-tests
|
|
title: ArchUnit guards Java multi-frontend boundaries
|
|
created: 2026-09-19
|
|
tags: [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 `implementation`s 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`
|