6.4 KiB
| id | ticket | title | status | created | ref_agenda | tags | ||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| DEC-0044 | multi-frontend-serializable-ir | Serializable common IR boundary | accepted | 2026-07-15 | AGD-0061 |
|
Context
IRBackend is already the common executable handoff between language frontends and common backend stages. Recent multi-frontend work locked the rule that PBS owns PBS-to-IRBackend lowering, while compiler-general specs own IRBackend -> IRVM lowering.
The next risk is not current PBS coupling. The risk is allowing the common handoff to grow around JVM object identity, callbacks, service references, mutable global state, implicit ordering, or cyclic object graphs. Any of those choices would make a future external frontend or out-of-process compiler boundary require a disruptive redesign.
This decision intentionally does not choose JSON, Protobuf, RPC, process isolation, plugin loading, or any concrete wire format. It defines only the data-shape discipline that keeps a future codec possible.
Decision
The common IRBackend handoff MUST remain serializable by design.
For this discussion, "serializable by design" means that public IRBackend contract types MUST be modelable as an acyclic, deterministic data graph made of:
- primitive values and strings;
- enums;
- immutable value objects;
- ordered lists;
- nullable or optional scalar fields only where absence is part of the contract;
- explicit identifier values for cross-references;
- and source attribution values such as file ids and spans.
The common IRBackend handoff MUST NOT expose, require, or rely on:
- callbacks, lambdas, service objects, registries, visitors, or live compiler services;
- frontend AST, parser, token, semantic, or editorial objects;
- mutable global state as part of interpretation;
- object identity equality as a semantic key;
- unordered collections where iteration order affects output;
- cyclic references between public handoff objects;
- lazy values whose result depends on current process state;
- or a selected wire format.
Cross-object references MUST use explicit ids or stable symbolic keys. Existing identifier wrappers such as FileId, ModuleId, CallableId, and IntrinsicId are acceptable when their meaning is table-scoped and deterministic. New typed ids SHOULD be introduced only when a concrete public handoff field otherwise depends on textual identity, object identity, or a direct object reference.
Ordered collections MUST preserve deterministic order. Any map-like data that becomes part of the handoff MUST either be represented as an ordered list of entries or define deterministic key ordering before it reaches the public contract.
The initial implementation MUST be an audit-and-guardrail pass, not a codec implementation. It MUST document the invariants, add lightweight tests that detect obvious violations, and correct concrete leaks only when the current public contract already exposes a non-serializable shape.
Rationale
This keeps the multi-frontend preparation narrow. A future external frontend needs a stable data contract before it needs a transport. Locking the data-shape discipline now prevents accidental coupling while avoiding premature infrastructure.
The current Java model already trends toward records, enums, ids, spans, and ordered lists. Requiring immediate structural migration everywhere would create churn before a real codec exists. Requiring auditability and guardrails gives the project a useful boundary now and leaves more invasive ID work for places where a leak is proven.
Object identity, service references, callbacks, and unordered iteration are especially harmful because they can work inside one JVM process while silently becoming undefined at a serialization boundary. Making those patterns forbidden in the public handoff keeps backend behavior reviewable and testable.
Implications
Specs must describe IRBackend as a language-neutral data contract, not as a live object graph. Compiler-general specs must own these invariants because they apply to all frontends. PBS specs may mention how PBS populates the handoff, but they must not define serialization rules for the common contract.
The code implementation must start by auditing public IRBackend model types under prometeu-compiler/prometeu-frontend-api/src/main/java/p/studio/compiler/models. The first guardrail should be reflection-based and focused on public fields, record components, constructors, and public methods of the handoff types.
Tests should check for forbidden frontend package exposure, forbidden service/callback shapes, public unordered collection exposure, and deterministic list ordering where aggregation or lowering depends on order. Existing tests such as IRBackendExecutableContractTest can be extended if that keeps the guardrail local and readable.
The implementation must not introduce a serializer, schema language, protocol, external process, or plugin runtime as part of this decision. Those remain future decisions.
Propagation Targets
- specs: update
docs/specs/compiler/20. IRBackend to IRVM Lowering Specification.mdwith a commonIRBackendserializability-by-design subsection; reference fromdocs/specs/compiler/22. Backend Spec-to-Test Conformance Matrix.mdif conformance rows are added. - plans: create one implementation plan covering spec update, public-contract audit, guardrail tests, and any concrete leak fixes discovered by the audit.
- code: inspect
prometeu-compiler/prometeu-frontend-api/src/main/java/p/studio/compiler/models/...first; inspect backend consumers only where a public handoff field or ordering rule requires confirmation. - tests: extend or add tests near
IRBackendExecutableContractTest; include deterministic ordering checks and public-contract reflection checks for non-serializable exposure. - docs: future lessons should teach the boundary as "data contract first, codec later" after implementation is complete.
References
- Agenda: AGD-0061
- Prior lesson:
discussion/lessons/DSC-0057-multi-frontend-frontend-backend-contract/LSN-0059-common-irbackend-handoff-and-backend-guardrails.md - Spec:
docs/specs/compiler/20. IRBackend to IRVM Lowering Specification.md - Spec:
docs/specs/compiler-languages/pbs/13. Lowering IRBackend Specification.md - Test:
prometeu-compiler/prometeu-frontend-api/src/test/java/p/studio/compiler/models/IRBackendExecutableContractTest.java