--- id: LSN-0055 ticket: multi-frontend-provider-contract title: Static frontend providers before plugin architecture created: 2026-07-15 tags: [compiler, compiler-general, studio, frontend, registry, multi-frontend] --- ## Context Prometeu needed a multi-frontend boundary without turning the compiler or Studio into a dynamic plugin platform. Before this work, shared code could ask the registry for frontend specs or phase services, and PBS was registered directly as the default language. That worked for a single frontend, but it made the next frontend harder because common code could still depend on PBS-specific construction details. The durable ownership rule is now: common compiler and Studio code select a frontend by `languageId`, then consume a provider contract. PBS remains the first and only real provider, but it is no longer the shape of the shared abstraction. ## Key Decisions ### `FrontendProvider` is the common registration unit **What:** Each registered frontend is represented by a `FrontendProvider` with: - `specification()`, for the static frontend contract and `languageId`; - `compiler()`, for compiler-facing frontend execution; - `languageService()`, as an optional editor-facing capability. **Why:** This groups the frontend identity, compiler entrypoint, and optional tooling capability without forcing every frontend to implement Studio/editor services. **Trade-offs:** The provider is intentionally small. It does not solve dynamic discovery, plugin installation, external loading, or all future language-service APIs. Those are separate architectural decisions. ### Registration is explicit **What:** Frontend registration is static and composition-root-owned. The application composition path bootstraps the default provider set, and the registry resolves providers by `languageId`. **Why:** Explicit registration keeps dependencies visible and testable. It lets composition know about PBS while preventing common compiler and Studio consumers from directly constructing PBS services. **Trade-offs:** Adding a new in-repository frontend still requires a code change in composition. That is acceptable because this decision optimizes for repository-internal multi-frontend readiness, not external plugin extensibility. ### PBS is a provider, not the shared model **What:** PBS is wrapped by `PBSFrontendProvider`. Shared build and Studio consumers obtain frontend behavior through `FrontendRegistryService.require(languageId)` or provider-derived listings. **Why:** PBS remains the correctness baseline, but it must not become the exclusive owner of compiler pipeline semantics. **Trade-offs:** PBS-specific tests may still instantiate `PBSFrontendPhaseService` directly because they test PBS internals. Common modules should not. ## Patterns and Algorithms Use this path for common compiler execution: 1. Resolve the project language from the manifest or default provider. 2. Resolve `FrontendProvider` by `languageId`. 3. Use `provider.specification()` for static metadata. 4. Use `provider.compiler()` for frontend compilation. 5. Use `provider.languageService()` only when a tooling consumer needs optional editor services. Use this path for Studio language catalogs: 1. List providers from the registry. 2. Derive templates from `provider.specification()`. 3. Do not hardcode PBS templates in Studio catalog code. ## Pitfalls - Do not add reflection, classpath scanning, external JAR loading, or runtime plugin installation to solve repository-internal frontend registration. - Do not make `languageService()` mandatory. Compilation and editor assistance are separate capabilities. - Do not instantiate `PBSFrontendPhaseService` from common build, dependency, Studio, or app code. - Do not use PBS as a fallback for unknown `languageId`. Unknown languages must fail explicitly. - Do not move frontend semantic ownership into Studio just because Studio consumes provider metadata. ## Takeaways - Static providers are enough to prepare for multiple in-repository frontends. - The registry boundary is provider-based, not PBS-based. - Composition may know which frontends exist; common consumers should only know `FrontendProvider`. - Optional editor capabilities keep compiler readiness independent from Studio feature depth.