Compare commits
No commits in common. "master" and "dev/multi-frontend-validation-boundaries" have entirely different histories.
master
...
dev/multi-
@ -1,9 +1,9 @@
|
|||||||
{"type":"meta","next_id":{"DSC":66,"AGD":69,"DEC":52,"PLN":131,"LSN":68,"CLSN":1}}
|
{"type":"meta","next_id":{"DSC":66,"AGD":69,"DEC":48,"PLN":127,"LSN":64,"CLSN":1}}
|
||||||
{"type":"discussion","id":"DSC-0065","status":"done","ticket":"multi-frontend-avoid-premature-abstractions","title":"Evitar abstracoes prematuras na preparacao multi-frontend","created_at":"2026-07-15","updated_at":"2026-09-19","tags":["compiler","compiler-general","studio","frontend","architecture","multi-frontend","simplicity"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0067","file":"discussion/lessons/DSC-0065-multi-frontend-avoid-premature-abstractions/LSN-0067-multi-frontend-phase-rejects-premature-infrastructure.md","status":"done","created_at":"2026-09-19","updated_at":"2026-09-19"}]}
|
{"type":"discussion","id":"DSC-0065","status":"open","ticket":"multi-frontend-avoid-premature-abstractions","title":"Evitar abstracoes prematuras na preparacao multi-frontend","created_at":"2026-07-15","updated_at":"2026-07-15","tags":["compiler","compiler-general","studio","frontend","architecture","multi-frontend","simplicity"],"agendas":[{"id":"AGD-0068","file":"AGD-0068-multi-frontend-avoid-premature-abstractions.md","status":"open","created_at":"2026-07-15","updated_at":"2026-07-15"}],"decisions":[],"plans":[],"lessons":[]}
|
||||||
{"type":"discussion","id":"DSC-0064","status":"done","ticket":"multi-frontend-architectural-tests","title":"Testes arquiteturais para fronteiras multi-frontend","created_at":"2026-07-15","updated_at":"2026-09-19","tags":["compiler","compiler-general","studio","frontend","architecture","tests","multi-frontend"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0066","file":"discussion/lessons/DSC-0064-multi-frontend-architectural-tests/LSN-0066-archunit-guards-java-multi-frontend-boundaries.md","status":"done","created_at":"2026-09-19","updated_at":"2026-09-19"}]}
|
{"type":"discussion","id":"DSC-0064","status":"open","ticket":"multi-frontend-architectural-tests","title":"Testes arquiteturais para fronteiras multi-frontend","created_at":"2026-07-15","updated_at":"2026-07-15","tags":["compiler","compiler-general","studio","frontend","architecture","tests","multi-frontend"],"agendas":[{"id":"AGD-0067","file":"AGD-0067-multi-frontend-architectural-tests.md","status":"open","created_at":"2026-07-15","updated_at":"2026-07-15"}],"decisions":[],"plans":[],"lessons":[]}
|
||||||
{"type":"discussion","id":"DSC-0063","status":"done","ticket":"multi-frontend-synthetic-test-frontend","title":"Frontend sintetico de teste para provar neutralidade do pipeline","created_at":"2026-07-15","updated_at":"2026-09-19","tags":["compiler","compiler-general","frontend","tests","backend","multi-frontend"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0065","file":"discussion/lessons/DSC-0063-multi-frontend-synthetic-test-frontend/LSN-0065-synthetic-test-frontend-proves-pipeline-neutrality.md","status":"done","created_at":"2026-09-19","updated_at":"2026-09-19"}]}
|
{"type":"discussion","id":"DSC-0063","status":"open","ticket":"multi-frontend-synthetic-test-frontend","title":"Frontend sintetico de teste para provar neutralidade do pipeline","created_at":"2026-07-15","updated_at":"2026-07-15","tags":["compiler","compiler-general","frontend","tests","backend","multi-frontend"],"agendas":[{"id":"AGD-0066","file":"AGD-0066-multi-frontend-synthetic-test-frontend.md","status":"open","created_at":"2026-07-15","updated_at":"2026-07-15"}],"decisions":[],"plans":[],"lessons":[]}
|
||||||
{"type":"discussion","id":"DSC-0062","status":"done","ticket":"multi-frontend-pvm-neutrality","title":"Neutralidade da PVM e identificacao PBX independente de PBS","created_at":"2026-07-15","updated_at":"2026-09-18","tags":["vm-arch","runtime","pvm","pbx","compiler","multi-frontend"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0061","file":"discussion/lessons/DSC-0062-multi-frontend-pvm-neutrality/LSN-0061-pbx-runtime-boundary.md","status":"done","created_at":"2026-09-18","updated_at":"2026-09-18"}]}
|
{"type":"discussion","id":"DSC-0062","status":"done","ticket":"multi-frontend-pvm-neutrality","title":"Neutralidade da PVM e identificacao PBX independente de PBS","created_at":"2026-07-15","updated_at":"2026-09-18","tags":["vm-arch","runtime","pvm","pbx","compiler","multi-frontend"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0061","file":"discussion/lessons/DSC-0062-multi-frontend-pvm-neutrality/LSN-0061-pbx-runtime-boundary.md","status":"done","created_at":"2026-09-18","updated_at":"2026-09-18"}]}
|
||||||
{"type":"discussion","id":"DSC-0061","status":"done","ticket":"multi-frontend-sdk-canonical-definition","title":"Auditoria e centralizacao gradual da definicao canonica do SDK","created_at":"2026-07-15","updated_at":"2026-09-19","tags":["compiler","compiler-general","sdk","stdlib","hostcalls","intrinsics","multi-frontend"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0064","file":"discussion/lessons/DSC-0061-multi-frontend-sdk-canonical-definition/LSN-0064-runtime-owns-console-abi-pbs-is-delivery.md","status":"done","created_at":"2026-09-19","updated_at":"2026-09-19"}]}
|
{"type":"discussion","id":"DSC-0061","status":"open","ticket":"multi-frontend-sdk-canonical-definition","title":"Auditoria e centralizacao gradual da definicao canonica do SDK","created_at":"2026-07-15","updated_at":"2026-07-15","tags":["compiler","compiler-general","sdk","stdlib","hostcalls","intrinsics","multi-frontend"],"agendas":[{"id":"AGD-0064","file":"AGD-0064-multi-frontend-sdk-canonical-definition.md","status":"open","created_at":"2026-07-15","updated_at":"2026-07-15"}],"decisions":[],"plans":[],"lessons":[]}
|
||||||
{"type":"discussion","id":"DSC-0060","status":"done","ticket":"multi-frontend-validation-boundaries","title":"Separar validacoes de linguagem e validacoes de plataforma","created_at":"2026-07-15","updated_at":"2026-09-19","tags":["compiler","compiler-general","compiler-pbs","backend","validation","multi-frontend"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0063","file":"discussion/lessons/DSC-0060-multi-frontend-validation-boundaries/LSN-0063-language-vs-platform-validation-ownership.md","status":"done","created_at":"2026-09-19","updated_at":"2026-09-19"}]}
|
{"type":"discussion","id":"DSC-0060","status":"done","ticket":"multi-frontend-validation-boundaries","title":"Separar validacoes de linguagem e validacoes de plataforma","created_at":"2026-07-15","updated_at":"2026-09-19","tags":["compiler","compiler-general","compiler-pbs","backend","validation","multi-frontend"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0063","file":"discussion/lessons/DSC-0060-multi-frontend-validation-boundaries/LSN-0063-language-vs-platform-validation-ownership.md","status":"done","created_at":"2026-09-19","updated_at":"2026-09-19"}]}
|
||||||
{"type":"discussion","id":"DSC-0059","status":"done","ticket":"multi-frontend-common-lifecycle","title":"Extrair lifecycle comum das responsabilidades do frontend PBS","created_at":"2026-07-15","updated_at":"2026-09-19","tags":["compiler","compiler-general","compiler-pbs","lifecycle","backend","multi-frontend"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0062","file":"discussion/lessons/DSC-0059-multi-frontend-common-lifecycle/LSN-0062-common-lifecycle-assembly-stage.md","status":"done","created_at":"2026-09-19","updated_at":"2026-09-19"}]}
|
{"type":"discussion","id":"DSC-0059","status":"done","ticket":"multi-frontend-common-lifecycle","title":"Extrair lifecycle comum das responsabilidades do frontend PBS","created_at":"2026-07-15","updated_at":"2026-09-19","tags":["compiler","compiler-general","compiler-pbs","lifecycle","backend","multi-frontend"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0062","file":"discussion/lessons/DSC-0059-multi-frontend-common-lifecycle/LSN-0062-common-lifecycle-assembly-stage.md","status":"done","created_at":"2026-09-19","updated_at":"2026-09-19"}]}
|
||||||
{"type":"discussion","id":"DSC-0058","status":"done","ticket":"multi-frontend-serializable-ir","title":"Manter a IR comum serializavel por design","created_at":"2026-07-15","updated_at":"2026-07-15","tags":["compiler","compiler-general","ir","backend","serialization","multi-frontend"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0060","file":"discussion/lessons/DSC-0058-multi-frontend-serializable-ir/LSN-0060-data-contract-first-for-serializable-irbackend.md","status":"done","created_at":"2026-07-15","updated_at":"2026-07-15"}]}
|
{"type":"discussion","id":"DSC-0058","status":"done","ticket":"multi-frontend-serializable-ir","title":"Manter a IR comum serializavel por design","created_at":"2026-07-15","updated_at":"2026-07-15","tags":["compiler","compiler-general","ir","backend","serialization","multi-frontend"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0060","file":"discussion/lessons/DSC-0058-multi-frontend-serializable-ir/LSN-0060-data-contract-first-for-serializable-irbackend.md","status":"done","created_at":"2026-07-15","updated_at":"2026-07-15"}]}
|
||||||
|
|||||||
@ -1,121 +0,0 @@
|
|||||||
---
|
|
||||||
id: LSN-0064
|
|
||||||
ticket: multi-frontend-sdk-canonical-definition
|
|
||||||
title: Runtime owns console ABI; PBS is delivery
|
|
||||||
created: 2026-09-19
|
|
||||||
tags: [compiler, compiler-general, sdk, stdlib, hostcalls, intrinsics, multi-frontend]
|
|
||||||
---
|
|
||||||
|
|
||||||
# Runtime owns console ABI; PBS is delivery
|
|
||||||
|
|
||||||
## Original Problem
|
|
||||||
|
|
||||||
"SDK" mixed three layers: platform ABI, PBS stdlib shells, and docs. The PBS
|
|
||||||
compiler reads `[Host]` and `[IntrinsicCall]` from `.pbs` files. It does not
|
|
||||||
read the runtime registry. Intrinsics already had a CSV in the runtime
|
|
||||||
repository, a handwritten Java enum, and a disabled parity test. Spec 8
|
|
||||||
documented `audio` and `@core:math`. Disk had `game/stdlib/1` with `color`,
|
|
||||||
`asset`, `composer`, `gfx`, `input`, and `log`. Spec 18 preferred `@sdk:*` for
|
|
||||||
host APIs while `@sdk:input` was a builtin.
|
|
||||||
|
|
||||||
There is no second language in this phase. The risk was not a missing generic
|
|
||||||
SDK. The risk was treating PBS shells, or a stale spec, as console ABI.
|
|
||||||
DEC-0047 had already classified canonical host identity as platform-owned and
|
|
||||||
left `PbsHostAdmissionValidator` in the PBS package until a shared source
|
|
||||||
existed.
|
|
||||||
|
|
||||||
## Consolidated Decision
|
|
||||||
|
|
||||||
This discussion was an audit. It published an authority map. It did not create
|
|
||||||
a canonical schema, generate bindings, enable intrinsic parity, or move the
|
|
||||||
host-admission validator.
|
|
||||||
|
|
||||||
The console has two distinct axes:
|
|
||||||
|
|
||||||
- VM-owned intrinsics, identity `canonical_name@version` plus `final_id`;
|
|
||||||
- host-backed calls, identity `(module, name, version)` plus capability.
|
|
||||||
|
|
||||||
Do not unify those axes into one catalog while PBS is the only frontend.
|
|
||||||
|
|
||||||
Conflict resolution:
|
|
||||||
|
|
||||||
- Intrinsic conflict: `runtime/docs/vm-arch/INTRINSICS.csv` wins. Studio
|
|
||||||
`docs/vm-arch/INTRINSICS.csv` is a mirror. `IRVMIntrinsicDefinition` is
|
|
||||||
derived. PBS `[BuiltinType]` / `[IntrinsicCall]` shells are delivery.
|
|
||||||
- Host conflict: runtime spec 16 and `SyscallMeta` win. PBS `[Host]` attributes
|
|
||||||
must not define ABI. They declare the shell the PBS compiler reads today.
|
|
||||||
|
|
||||||
`@sdk:*` / `@core:*` paths must not imply ownership. `@sdk:input` is a
|
|
||||||
registered builtin exception. It was not moved to `@core`.
|
|
||||||
|
|
||||||
PBS conformance means PBS shells and docs match runtime ABI, not the reverse.
|
|
||||||
`PbsHostAdmissionValidator` may stay in the PBS package. `E_HOST_*` is not
|
|
||||||
eternal PBS semantics.
|
|
||||||
|
|
||||||
## Final Implementation
|
|
||||||
|
|
||||||
The work was editorial and test-facing.
|
|
||||||
|
|
||||||
Spec 18 now states that PBS stdlib is delivery and must not define syscall IDs,
|
|
||||||
intrinsic `final_id` values, or `SyscallMeta`. Runtime catalogs outrank it.
|
|
||||||
`@sdk:input` is recorded as the current builtin exception.
|
|
||||||
|
|
||||||
Spec 8 now documents `<target>/stdlib/<N>/...` with current line `1` at
|
|
||||||
`game/stdlib/1`: `core/color` and `sdk/{asset,composer,gfx,input,log}`. It no
|
|
||||||
longer ships `audio` or `@core:math` as current modules.
|
|
||||||
|
|
||||||
Spec 6.2 now requires PBS host shells to repeat the runtime registry and forbids
|
|
||||||
inventing `(module, name, version)`. The authority example is
|
|
||||||
`("gfx2d", "clear", 1)`.
|
|
||||||
|
|
||||||
`ConsoleAbiAuthoritySpecTest` locks those sentences. No production compiler
|
|
||||||
code, stdlib `.pbs`, or validator package moved. The intrinsic parity test
|
|
||||||
stays disabled.
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
Runtime wins:
|
|
||||||
|
|
||||||
- `color.rgb@1` / `final_id` `0x1101` come from `INTRINSICS.csv`;
|
|
||||||
- `("gfx2d", "clear", 1)` and `("asset", "load", 1)` come from `SyscallMeta`.
|
|
||||||
|
|
||||||
PBS delivers, and does not own, those identities:
|
|
||||||
|
|
||||||
- `@core:color` with `[BuiltinType(name = "color", version = 1)]`;
|
|
||||||
- `@sdk:gfx` `LowGfx.clear` with `[Host(module = "gfx2d", name = "clear", version = 1)]`;
|
|
||||||
- `@sdk:input` with `[BuiltinType]` / `[IntrinsicCall]` under `@sdk`.
|
|
||||||
|
|
||||||
Stale docs that the recut removed as current line-1 inventory:
|
|
||||||
|
|
||||||
- `stdlib/1/sdk/audio`;
|
|
||||||
- `@core:math` as a packaged module.
|
|
||||||
|
|
||||||
## Pitfalls
|
|
||||||
|
|
||||||
- Do not treat PBS stdlib as the ABI catalog because the compiler already reads
|
|
||||||
it. That is convenience, not authority.
|
|
||||||
- Do not create `HOSTCALLS.csv` or generate the Java enum because the map now
|
|
||||||
exists. A catalog waits on a second consumer.
|
|
||||||
- Do not move `PbsHostAdmissionValidator` on the strength of this map. DEC-0047
|
|
||||||
classified identity as platform; this discussion published who wins; the
|
|
||||||
validator still has no shared catalog to consume.
|
|
||||||
- Do not read `@sdk` as host and `@core` as VM. Path is packaging. `@sdk:input`
|
|
||||||
is builtin.
|
|
||||||
- Do not enable `IRVMIntrinsicRegistryParityTest` as a side effect of a doc
|
|
||||||
recut. That is compiler/runtime sync, not PBS packaging conformance.
|
|
||||||
- Do not put the authority map only in a decision. Housekeep deletes workflow
|
|
||||||
artifacts. Specs and this lesson keep the map.
|
|
||||||
|
|
||||||
## References
|
|
||||||
|
|
||||||
- Decision: `DEC-0048`
|
|
||||||
- Plan: `PLN-0127`
|
|
||||||
- Related lesson: `LSN-0063` - Language vs platform validation ownership
|
|
||||||
- Related lesson: `LSN-0061` - PBX is the language-neutral runtime boundary
|
|
||||||
- `docs/specs/compiler/18. Standard Library Surface Specification.md`
|
|
||||||
- `docs/specs/compiler-languages/pbs/8. Stdlib Environment Packaging and Loading Specification.md`
|
|
||||||
- `docs/specs/compiler-languages/pbs/6.2. Host ABI Binding and Loader Resolution Specification.md`
|
|
||||||
- `docs/vm-arch/README.md`
|
|
||||||
- `../runtime/docs/vm-arch/INTRINSICS.csv`
|
|
||||||
- `../runtime/docs/specs/runtime/16-host-abi-and-syscalls.md`
|
|
||||||
- `prometeu-compiler/prometeu-build-pipeline/src/test/java/p/studio/compiler/specs/ConsoleAbiAuthoritySpecTest.java`
|
|
||||||
@ -1,148 +0,0 @@
|
|||||||
---
|
|
||||||
id: LSN-0065
|
|
||||||
ticket: multi-frontend-synthetic-test-frontend
|
|
||||||
title: Synthetic test frontend proves common pipeline neutrality
|
|
||||||
created: 2026-09-19
|
|
||||||
tags: [compiler, compiler-general, frontend, tests, backend, multi-frontend]
|
|
||||||
---
|
|
||||||
|
|
||||||
# Synthetic test frontend proves common pipeline neutrality
|
|
||||||
|
|
||||||
## Original Problem
|
|
||||||
|
|
||||||
The common pipeline already had `FrontendProvider`, `IRBackend` as the
|
|
||||||
executable handoff, common lifecycle assembly, and `IRBackend -> IRVM -> PBX`.
|
|
||||||
Direct construction tests proved the backend could lower a handmade
|
|
||||||
`IRBackend`. Import guards proved common backend code did not depend on PBS
|
|
||||||
packages.
|
|
||||||
|
|
||||||
That was not enough. Nothing proved that a second provider, resolved by
|
|
||||||
`languageId`, could enter through `DiscoverPhase` and
|
|
||||||
`FrontendPhasePipelineStage`, assemble lifecycle, and finish
|
|
||||||
`BuilderPipelineService.compile()` at verified bytecode without instantiating
|
|
||||||
PBS, reading `.pbs` files, or loading PBS stdlib.
|
|
||||||
|
|
||||||
`CompileOnlyFrontendProvider` already existed as a local test double. It was
|
|
||||||
not registered, returned an empty `IRBackend`, and never called the pipeline.
|
|
||||||
It did not close this gap.
|
|
||||||
|
|
||||||
## Consolidated Decision
|
|
||||||
|
|
||||||
Pipeline neutrality is proved by a **test-only** compile-only
|
|
||||||
`FrontendProvider`, not by a second product language and not by injecting IR
|
|
||||||
into compile stages.
|
|
||||||
|
|
||||||
Locked shape (former Option A):
|
|
||||||
|
|
||||||
- `languageId` is `synth`.
|
|
||||||
- The provider and `FrontendPhaseService` live only in
|
|
||||||
`prometeu-build-pipeline` test sources.
|
|
||||||
- `languageService()` is empty. There is no parser, grammar, semantic
|
|
||||||
presentation, or stdlib catalog.
|
|
||||||
- `sourceRoots` is `src`. `allowedExtensions` must not collide with `pbs` /
|
|
||||||
`barrel`. The fixture must **not** create a source file of that extension.
|
|
||||||
An empty `src/` directory must still exist because `WireProjectsPhase`
|
|
||||||
resolves `toRealPath()`.
|
|
||||||
- The compiler ignores source text and emits one module, one `frame` body
|
|
||||||
that is a single `RET`, and an `IRLifecycleDeclaration` with exactly one
|
|
||||||
`FRAME_ROOT` whose origin span is filled.
|
|
||||||
- The handoff must not declare `FILE_INIT_FRAGMENT` or `PROJECT_INIT`, and
|
|
||||||
must not pre-materialize wrappers, module-init, or `BOOT_GUARD`. The common
|
|
||||||
assembler produces `__prometeu.lifecycle.frame_wrapper$mN` and the boot
|
|
||||||
guard.
|
|
||||||
- The IR must not contain host bindings, capabilities, intrinsics, PBS types,
|
|
||||||
PBS stdlib, or `__pbs.` names.
|
|
||||||
|
|
||||||
The acceptance path is `compile()` through `VerifyBytecode`. Writing
|
|
||||||
`program.pbx` is not the criterion. `build()` only adds disk I/O.
|
|
||||||
|
|
||||||
Registration stays on the existing static `FrontendRegistryService`.
|
|
||||||
`register` and `unregister` are public. `unregister` refuses to remove the
|
|
||||||
default PBS provider and is a no-op for unknown ids. Tests register `synth`
|
|
||||||
for the duration of the run and unregister in `try/finally`.
|
|
||||||
`bootstrapDefaults()`, `AppContainer`, and the Studio language catalog must
|
|
||||||
not register `synth`.
|
|
||||||
|
|
||||||
Do not inject a `Registry` into the pipeline, add a `frontends/synth` module,
|
|
||||||
scan the classpath, or treat a dummy on-disk extension as a language. Do not
|
|
||||||
replace `LifecycleAssemblerServiceTest`, `LowerToIRVMServiceTest`, or
|
|
||||||
`IRBackendExecutableContractTest` with this fixture.
|
|
||||||
|
|
||||||
A blank `prometeu.json` `language` field still defaults to PBS. The synthetic
|
|
||||||
project must set `language: synth` explicitly.
|
|
||||||
|
|
||||||
## Final Implementation
|
|
||||||
|
|
||||||
`FrontendRegistryService.register(FrontendProvider)` is the explicit
|
|
||||||
registration API. `unregister(String languageId)` removes a non-PBS provider
|
|
||||||
or no-ops if the id is absent. Duplicate `register` still fails.
|
|
||||||
`bootstrapDefaults()` still registers only PBS.
|
|
||||||
|
|
||||||
The test fixture is:
|
|
||||||
|
|
||||||
- `p.studio.compiler.synth.SyntheticFrontendProvider`
|
|
||||||
- `p.studio.compiler.synth.SyntheticFrontendPhaseService`
|
|
||||||
|
|
||||||
`SyntheticFrontendPipelineTest` writes a temporary project
|
|
||||||
(`language: synth`, `target: Game`, numeric `stdlib`, empty `src/`),
|
|
||||||
registers the provider, calls `BuilderPipelineService.compile()`, and
|
|
||||||
asserts:
|
|
||||||
|
|
||||||
- the synthetic compiler ran;
|
|
||||||
- resolved `languageId` is `synth`, not `pbs`;
|
|
||||||
- diagnostics have no errors;
|
|
||||||
- in-memory bytecode is non-empty and verified;
|
|
||||||
- assembled entrypoint is `__prometeu.lifecycle.frame_wrapper$m0`;
|
|
||||||
- a hidden boot guard is present;
|
|
||||||
- no `__pbs.` names;
|
|
||||||
- no `.pbs` / `.barrel` sources were required;
|
|
||||||
- after `unregister`, `listProviders()` is PBS-only.
|
|
||||||
|
|
||||||
Spec 23 section 8.3 records that a compile-only registered provider is a
|
|
||||||
valid pipeline participant and that the common pipeline must not require PBS
|
|
||||||
types, PBS sources, or PBS stdlib to emit verified bytecode. Spec 22 row
|
|
||||||
`G23-8.3` binds that obligation to the synthetic pipeline test.
|
|
||||||
|
|
||||||
PBS production code, Studio, and `AppContainer` were not changed.
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
Good:
|
|
||||||
|
|
||||||
- register `synth`, compile a temp project with empty `src/`, unregister;
|
|
||||||
- `FRAME_ROOT` with `FileId(0)` and a non-none span, even with no source file
|
|
||||||
in `FileTable`;
|
|
||||||
- assert the synthetic compiler was invoked instead of importing
|
|
||||||
`PBSFrontendPhaseService` from build-pipeline tests.
|
|
||||||
|
|
||||||
Bad:
|
|
||||||
|
|
||||||
- omitting `language` in the manifest so discovery silently uses PBS;
|
|
||||||
- creating `main.dummy` and calling that a second frontend;
|
|
||||||
- putting the provider under `prometeu-compiler/frontends/`;
|
|
||||||
- leaving `synth` registered after the test so later tests see two providers;
|
|
||||||
- using this pipeline test as a substitute for assembler or IRVM unit tests.
|
|
||||||
|
|
||||||
## Pitfalls
|
|
||||||
|
|
||||||
- `WireProjectsPhase` still needs `src/` on disk. Empty is not the same as
|
|
||||||
missing.
|
|
||||||
- Origin span `Span.none()` is rejected by the assembler. Use a real
|
|
||||||
`FileId` even when no file was loaded.
|
|
||||||
- `unregister("pbs")` must fail. A cleanup path that blindly unregisters the
|
|
||||||
resolved language would delete the product default.
|
|
||||||
- `listProviders()` feeds the Studio catalog. A leaked test registration
|
|
||||||
would show `synth` as a new-project language.
|
|
||||||
- Direct `IRBackend` construction tests still own backend-only proofs. The
|
|
||||||
synthetic frontend owns the registry-plus-pipeline proof. Keep both.
|
|
||||||
|
|
||||||
## References
|
|
||||||
|
|
||||||
- Decision: `DEC-0049`
|
|
||||||
- Plan: `PLN-0128`
|
|
||||||
- Related lessons: `LSN-0055`, `LSN-0056`, `LSN-0059`, `LSN-0062`, `LSN-0061`
|
|
||||||
- `docs/specs/compiler/23. Compiler Pipeline Entry Points Specification.md`
|
|
||||||
- `docs/specs/compiler/22. Backend Spec-to-Test Conformance Matrix.md`
|
|
||||||
- `prometeu-compiler/prometeu-frontend-registry/src/main/java/p/studio/compiler/FrontendRegistryService.java`
|
|
||||||
- `prometeu-compiler/prometeu-build-pipeline/src/test/java/p/studio/compiler/synth/SyntheticFrontendProvider.java`
|
|
||||||
- `prometeu-compiler/prometeu-build-pipeline/src/test/java/p/studio/compiler/integration/SyntheticFrontendPipelineTest.java`
|
|
||||||
@ -1,151 +0,0 @@
|
|||||||
---
|
|
||||||
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`
|
|
||||||
@ -1,167 +0,0 @@
|
|||||||
---
|
|
||||||
id: LSN-0067
|
|
||||||
ticket: multi-frontend-avoid-premature-abstractions
|
|
||||||
title: Multi-frontend phase rejects premature infrastructure
|
|
||||||
created: 2026-09-19
|
|
||||||
tags: [compiler, compiler-general, studio, frontend, architecture, multi-frontend, simplicity]
|
|
||||||
---
|
|
||||||
|
|
||||||
# Multi-frontend phase rejects premature infrastructure
|
|
||||||
|
|
||||||
## Original Problem
|
|
||||||
|
|
||||||
The multi-frontend preparation needed a standing simplicity rule. The original
|
|
||||||
agenda asked for that rule *before* the other multi-frontend discussions.
|
|
||||||
Those discussions already closed (DSC-0054 through DSC-0064). The remaining
|
|
||||||
risk was not a missing plugin platform.
|
|
||||||
|
|
||||||
The remaining risk was twofold:
|
|
||||||
|
|
||||||
1. using "keep it simple" to put PBS construction back into common compiler,
|
|
||||||
Studio, LSP, or app code;
|
|
||||||
2. inventing marketplace, JAR loading, RPC, validator-core, or a generic SPI
|
|
||||||
"for a future language" that does not exist in this repository.
|
|
||||||
|
|
||||||
`FrontendRegistryService` is a static singleton. The original agenda listed
|
|
||||||
a global service locator as out of scope. Without an explicit exception, a
|
|
||||||
later change could inject a `Registry` into the pipeline for purity, which
|
|
||||||
DSC-0063 already refused.
|
|
||||||
|
|
||||||
## Consolidated Decision
|
|
||||||
|
|
||||||
This is standing policy for *future* work in the current phase: PBS as the
|
|
||||||
only product frontend, `synth` as a test-only provider, frontends in-repo.
|
|
||||||
It is not an audit of closed discussions and must not rewrite them.
|
|
||||||
|
|
||||||
Durable locks from DEC-0051:
|
|
||||||
|
|
||||||
- Implementation of this discussion is the decision plus this lesson. There
|
|
||||||
is no new spec, no new ArchUnit rule, and no production refactor.
|
|
||||||
- Spec 23 §2 and §8.3 remain the discovery MUST NOT surface. Do not copy
|
|
||||||
those sentences into a new spec.
|
|
||||||
- Architectural tests stay owned by LSN-0066.
|
|
||||||
|
|
||||||
### Static registry is allowed
|
|
||||||
|
|
||||||
`FrontendRegistryService` as a static singleton, with public `register` and
|
|
||||||
`unregister` and `bootstrapDefaults()` registering only PBS, is the
|
|
||||||
composition mechanism of this phase. Treat that as an explicit exception,
|
|
||||||
not as a banned service locator.
|
|
||||||
|
|
||||||
Discovery must not use `ServiceLoader`, classpath scanning, reflection-based
|
|
||||||
discovery, an external JAR, or runtime plugin installation.
|
|
||||||
|
|
||||||
Do not inject a `Registry` into the pipeline, LSP, or `AppContainer`.
|
|
||||||
`AppContainer` is not a PBS composition root. It may call
|
|
||||||
`FrontendRegistryService.bootstrapDefaults()`. It must not instantiate PBS
|
|
||||||
types.
|
|
||||||
|
|
||||||
### Real in-repo consumer
|
|
||||||
|
|
||||||
A new interface, module, SPI, generator, or framework is allowed only when
|
|
||||||
a real in-repo consumer exists. In this phase that consumer is one of:
|
|
||||||
|
|
||||||
- the PBS product frontend;
|
|
||||||
- the `synth` test frontend;
|
|
||||||
- a second product frontend accepted by its own decision.
|
|
||||||
|
|
||||||
"For a future language", "for the marketplace", or "when we have plugins"
|
|
||||||
is not a consumer.
|
|
||||||
|
|
||||||
`FrontendProvider`, `IRBackend`, common lifecycle assembly, and test-only
|
|
||||||
ArchUnit are not premature. They already have consumers.
|
|
||||||
|
|
||||||
### Forbidden in this phase
|
|
||||||
|
|
||||||
Until a later decision authorizes it with a real consumer, do not introduce:
|
|
||||||
|
|
||||||
1. dynamic frontend discovery (plugin, `ServiceLoader`, scan, external JAR,
|
|
||||||
runtime install);
|
|
||||||
2. RPC, sockets, a process supervisor, or version negotiation between
|
|
||||||
compiler and frontend;
|
|
||||||
3. a marketplace, hot reload, or frontend sandbox;
|
|
||||||
4. a validator-core or generic validation framework;
|
|
||||||
5. an SDK schema/generator or `HOSTCALLS.csv` as canonical ABI (LSN-0064);
|
|
||||||
6. a product module `frontends/synth`;
|
|
||||||
7. an injected `Registry`, or `AppContainer` as the PBS composition root.
|
|
||||||
|
|
||||||
This list is not a monorepo-wide simplicity charter. It does not govern
|
|
||||||
JavaFX, packer, or LSP protocol design. Owner is `compiler/general`, with
|
|
||||||
impact on `studio` on the multi-frontend axis.
|
|
||||||
|
|
||||||
### Neighbors stay closed
|
|
||||||
|
|
||||||
Do not reinterpret, relax, "simplify", or reimplement:
|
|
||||||
|
|
||||||
- provider/registry (LSN-0055 / spec 23 §8.3);
|
|
||||||
- common lifecycle;
|
|
||||||
- console ABI / PBS delivery;
|
|
||||||
- `synth`;
|
|
||||||
- ArchUnit / PBS module identity.
|
|
||||||
|
|
||||||
Using this policy to keep `new PBSFrontendPhaseService()` (or equivalent)
|
|
||||||
in common code is refused. That is PBS recoupling, not simplicity.
|
|
||||||
|
|
||||||
A second product frontend needs its own decision. This lesson neither
|
|
||||||
replaces that decision nor blocks it.
|
|
||||||
|
|
||||||
## Final Implementation
|
|
||||||
|
|
||||||
No production Java, Gradle, spec, or ArchUnit file changed.
|
|
||||||
|
|
||||||
The map above is the implementation. Future compiler/studio plans on this
|
|
||||||
axis should cite it when they propose a new module, SPI, or discovery
|
|
||||||
mechanism.
|
|
||||||
|
|
||||||
Code that already matches the phase:
|
|
||||||
|
|
||||||
- `FrontendProvider` exposes `specification()`, `compiler()`, and optional
|
|
||||||
`languageService()`;
|
|
||||||
- `FrontendRegistryService.bootstrapDefaults()` registers PBS only;
|
|
||||||
- `AppContainer` only calls that bootstrap;
|
|
||||||
- `synth` lives in build-pipeline test sources;
|
|
||||||
- ArchUnit lives in `:prometeu-architecture-tests`.
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
Good:
|
|
||||||
|
|
||||||
- add a method to `FrontendProvider` because PBS or `synth` cannot compile
|
|
||||||
or register without it;
|
|
||||||
- keep `unregister` on the static registry so `synth` tests can clean up;
|
|
||||||
- reject a proposal to load language JARs from a plugin directory.
|
|
||||||
|
|
||||||
Bad:
|
|
||||||
|
|
||||||
- inject `Registry` into `BuilderPipelineService` because static state looks
|
|
||||||
like a service locator;
|
|
||||||
- create `frontends/synth` as a product module;
|
|
||||||
- add validator-core "so the next language has somewhere to put checks";
|
|
||||||
- keep `new PBSFrontendPhaseService()` in pipeline code and call that
|
|
||||||
simpler than going through the provider.
|
|
||||||
|
|
||||||
## Pitfalls
|
|
||||||
|
|
||||||
- The original agenda order ("before the other agendas") is historical.
|
|
||||||
Do not reopen DSC-0054..DSC-0064 to satisfy it.
|
|
||||||
- Static registry plus explicit `register`/`unregister` is visible. Hidden
|
|
||||||
`ServiceLoader` discovery is not the same thing.
|
|
||||||
- A second product frontend *is* a real consumer. Do not use this lesson to
|
|
||||||
refuse that frontend; use it to refuse infrastructure that frontend does
|
|
||||||
not yet need.
|
|
||||||
- Spec 23 already forbids plugin discovery. Do not duplicate it. Do not
|
|
||||||
treat silence in spec 23 as permission for RPC or validator-core.
|
|
||||||
- Simplicity does not mean PBS may leak into common modules. LSN-0066 still
|
|
||||||
owns that boundary.
|
|
||||||
|
|
||||||
## References
|
|
||||||
|
|
||||||
- Decision: `DEC-0051`
|
|
||||||
- Plan: `PLN-0130`
|
|
||||||
- Related lessons: `LSN-0055`, `LSN-0060`, `LSN-0063`, `LSN-0064`,
|
|
||||||
`LSN-0065`, `LSN-0066`
|
|
||||||
- `docs/specs/compiler/23. Compiler Pipeline Entry Points Specification.md`
|
|
||||||
(§2, §8.3)
|
|
||||||
- `prometeu-compiler/prometeu-frontend-registry/src/main/java/p/studio/compiler/FrontendRegistryService.java`
|
|
||||||
- `prometeu-compiler/prometeu-frontend-api/src/main/java/p/studio/compiler/services/FrontendProvider.java`
|
|
||||||
- `prometeu-app/src/main/java/p/studio/AppContainer.java`
|
|
||||||
@ -0,0 +1,78 @@
|
|||||||
|
---
|
||||||
|
id: AGD-0064
|
||||||
|
ticket: multi-frontend-sdk-canonical-definition
|
||||||
|
title: Auditoria e centralizacao gradual da definicao canonica do SDK
|
||||||
|
status: open
|
||||||
|
created: 2026-07-15
|
||||||
|
resolved:
|
||||||
|
decision:
|
||||||
|
tags: [compiler, compiler-general, sdk, stdlib, hostcalls, intrinsics, multi-frontend]
|
||||||
|
---
|
||||||
|
|
||||||
|
# Agenda - Centralizar a definicao do SDK
|
||||||
|
|
||||||
|
## Objetivo
|
||||||
|
|
||||||
|
Domain owner: `compiler/general`, com referencias a `compiler/pbs` e `vm-arch`.
|
||||||
|
|
||||||
|
Auditar onde hostcalls, intrinsics, tipos fundamentais e APIs do console sao definidos hoje antes de propor uma fonte canonica do SDK.
|
||||||
|
|
||||||
|
## Contexto atual
|
||||||
|
|
||||||
|
Existem specs em `docs/vm-arch/INTRINSICS.csv`, docs de stdlib em `docs/specs/compiler/18. Standard Library Surface Specification.md`, specs PBS de stdlib e host ABI, alem de possiveis registries em codigo e fixtures.
|
||||||
|
|
||||||
|
## Escopo
|
||||||
|
|
||||||
|
- Mapear fontes atuais da verdade.
|
||||||
|
- Identificar definicoes geradas, duplicadas e manuais.
|
||||||
|
- Propor caminho gradual para um schema canonico.
|
||||||
|
|
||||||
|
## Fora de escopo
|
||||||
|
|
||||||
|
- Migracao grande do SDK.
|
||||||
|
- Gerar bindings para C#, Kotlin, TypeScript ou outras linguagens.
|
||||||
|
- Escolher formato definitivo antes da auditoria.
|
||||||
|
|
||||||
|
## Arquivos e componentes a inspecionar
|
||||||
|
|
||||||
|
- `docs/vm-arch/INTRINSICS.csv`
|
||||||
|
- `docs/specs/compiler/18. Standard Library Surface Specification.md`
|
||||||
|
- `docs/specs/compiler-languages/pbs/5. Manifest, Stdlib, and SDK Resolution Specification.md`
|
||||||
|
- `docs/specs/compiler-languages/pbs/6.1. Intrinsics and Builtin Types Specification.md`
|
||||||
|
- `prometeu-compiler/...` registries de hostcalls/intrinsics/stdlib
|
||||||
|
- runtime/PVM quando presente no workspace ou submodulos relacionados
|
||||||
|
|
||||||
|
## Alteracoes propostas
|
||||||
|
|
||||||
|
Opcao A: agenda de auditoria pura, produzindo mapa de fontes e duplicacoes.
|
||||||
|
|
||||||
|
Opcao B: criar schema canonico minimo depois da auditoria, sem migrar todos os consumidores.
|
||||||
|
|
||||||
|
Recomendacao inicial: primeiro fechar auditoria; so uma decision posterior deve escolher formato e migracao.
|
||||||
|
|
||||||
|
## Estrategia de implementacao
|
||||||
|
|
||||||
|
Listar cada hostcall/intrinsic/tipo fundamental em suas fontes atuais, comparar assinatura, capability, versao e docs, e classificar divergencias.
|
||||||
|
|
||||||
|
## Testes necessarios
|
||||||
|
|
||||||
|
- Testes de paridade entre registry runtime/backend e specs existentes, se ja houver fonte estruturada.
|
||||||
|
- Testes de nao divergencia para IDs e assinaturas apos qualquer centralizacao.
|
||||||
|
|
||||||
|
## Criterios de aceitacao
|
||||||
|
|
||||||
|
- Existe mapa claro de fonte real da verdade.
|
||||||
|
- Duplicacoes e divergencias ficam registradas.
|
||||||
|
- Nenhuma migracao ampla e iniciada sem nova decisao.
|
||||||
|
|
||||||
|
## Riscos
|
||||||
|
|
||||||
|
- Tratar docs como fonte real quando o codigo ja diverge.
|
||||||
|
- Iniciar geracao antes de saber quem consome cada definicao.
|
||||||
|
|
||||||
|
## Decisoes que devem ser registradas
|
||||||
|
|
||||||
|
- Fonte canonica proposta.
|
||||||
|
- Campos obrigatorios do SDK.
|
||||||
|
- Sequencia de migracao segura.
|
||||||
|
|
||||||
@ -0,0 +1,77 @@
|
|||||||
|
---
|
||||||
|
id: AGD-0066
|
||||||
|
ticket: multi-frontend-synthetic-test-frontend
|
||||||
|
title: Frontend sintetico de teste para provar neutralidade do pipeline
|
||||||
|
status: open
|
||||||
|
created: 2026-07-15
|
||||||
|
resolved:
|
||||||
|
decision:
|
||||||
|
tags: [compiler, compiler-general, frontend, tests, backend, multi-frontend]
|
||||||
|
---
|
||||||
|
|
||||||
|
# Agenda - Criar um frontend sintetico de teste
|
||||||
|
|
||||||
|
## Objetivo
|
||||||
|
|
||||||
|
Domain owner: `compiler/general`.
|
||||||
|
|
||||||
|
Discutir um frontend exclusivo de testes que prove que o pipeline comum nao depende implicitamente do PBS.
|
||||||
|
|
||||||
|
## Contexto atual
|
||||||
|
|
||||||
|
O criterio arquitetural final exige que um frontend sintetico implemente contratos equivalentes a `FrontendProvider`, `FrontendSpec` e `FrontendCompiler`, produza IR comum minima e passe pelo backend ate PBX/verifier.
|
||||||
|
|
||||||
|
## Escopo
|
||||||
|
|
||||||
|
- Escolher entre frontend totalmente sintetico ou extensao ficticia.
|
||||||
|
- Definir fixture de IR minima com `frame` vazio.
|
||||||
|
- Garantir isolamento em testes.
|
||||||
|
|
||||||
|
## Fora de escopo
|
||||||
|
|
||||||
|
- Expor frontend sintetico no Studio.
|
||||||
|
- Criar segunda linguagem real.
|
||||||
|
- Criar parser completo ou grammar dummy complexa.
|
||||||
|
|
||||||
|
## Arquivos e componentes a inspecionar
|
||||||
|
|
||||||
|
- `prometeu-compiler/prometeu-frontend-registry/...`
|
||||||
|
- `prometeu-compiler/prometeu-build-pipeline/...`
|
||||||
|
- testes do build pipeline e backend
|
||||||
|
- `prometeu-studio/src/main/java/p/studio/projects/...` apenas se a selecao por extensao for exercitada
|
||||||
|
|
||||||
|
## Alteracoes propostas
|
||||||
|
|
||||||
|
Opcao A: provider sintetico que ignora arquivos e retorna IR minima diretamente.
|
||||||
|
|
||||||
|
Opcao B: extensao `.dummy` reconhecida em fixture, com conteudo ignorado ou trivial.
|
||||||
|
|
||||||
|
Recomendacao inicial: preferir Opcao A para provar neutralidade do pipeline sem criar outra superficie de linguagem.
|
||||||
|
|
||||||
|
## Estrategia de implementacao
|
||||||
|
|
||||||
|
Esperar provider/IR/lifecycle estarem suficientemente definidos, entao adicionar fixture de teste que registra provider sintetico e executa pipeline comum sem PBS.
|
||||||
|
|
||||||
|
## Testes necessarios
|
||||||
|
|
||||||
|
- Provider registrado e resolvido por `languageId`.
|
||||||
|
- Extensao/source handling testado se a opcao B for escolhida.
|
||||||
|
- IR comum produzida, lifecycle montado, IRVM gerado, PBX emitido e verificado.
|
||||||
|
|
||||||
|
## Criterios de aceitacao
|
||||||
|
|
||||||
|
- Teste falha se pipeline comum instanciar PBS implicitamente.
|
||||||
|
- Synthetic frontend existe apenas em test fixtures.
|
||||||
|
- PBS nao e afetado.
|
||||||
|
|
||||||
|
## Riscos
|
||||||
|
|
||||||
|
- Fixture sintetica exercitar caminho feliz pequeno demais e nao proteger acoplamentos reais.
|
||||||
|
- Virar uma segunda linguagem informal.
|
||||||
|
|
||||||
|
## Decisoes que devem ser registradas
|
||||||
|
|
||||||
|
- Forma do frontend sintetico.
|
||||||
|
- Escopo minimo da IR fixture.
|
||||||
|
- Onde o provider de teste pode ser registrado.
|
||||||
|
|
||||||
@ -0,0 +1,79 @@
|
|||||||
|
---
|
||||||
|
id: AGD-0067
|
||||||
|
ticket: multi-frontend-architectural-tests
|
||||||
|
title: Testes arquiteturais para fronteiras multi-frontend
|
||||||
|
status: open
|
||||||
|
created: 2026-07-15
|
||||||
|
resolved:
|
||||||
|
decision:
|
||||||
|
tags: [compiler, compiler-general, studio, frontend, architecture, tests, multi-frontend]
|
||||||
|
---
|
||||||
|
|
||||||
|
# Agenda - Criar testes arquiteturais
|
||||||
|
|
||||||
|
## Objetivo
|
||||||
|
|
||||||
|
Domain owner: `compiler/general`, com impacto em `studio` e `vm-arch`.
|
||||||
|
|
||||||
|
Definir testes que protejam fronteiras: backend comum sem PBS, IR comum sem AST PBS, Studio comum sem instanciacao PBS fora do composition root e runtime neutro.
|
||||||
|
|
||||||
|
## Contexto atual
|
||||||
|
|
||||||
|
O repo ja tem testes Java para backend, bytecode e IRVM. ArchUnit pode ser util, mas o alinhamento proibe adicionar biblioteca arquitetural quando testes simples bastarem.
|
||||||
|
|
||||||
|
## Escopo
|
||||||
|
|
||||||
|
- Escolher ferramenta minima.
|
||||||
|
- Definir regras por pacote.
|
||||||
|
- Adicionar testes que sejam baratos e claros.
|
||||||
|
|
||||||
|
## Fora de escopo
|
||||||
|
|
||||||
|
- Cobrir toda arquitetura do monorepo.
|
||||||
|
- Adicionar ArchUnit sem justificativa concreta.
|
||||||
|
- Bloquear referencias PBS em testes PBS ou no frontend PBS.
|
||||||
|
|
||||||
|
## Arquivos e componentes a inspecionar
|
||||||
|
|
||||||
|
- `build.gradle.kts` e version catalog se houver.
|
||||||
|
- `prometeu-compiler/prometeu-build-pipeline/src/test/java/...`
|
||||||
|
- `prometeu-compiler/frontends/prometeu-frontend-pbs/src/test/java/...`
|
||||||
|
- `prometeu-studio/src/test/java/...`
|
||||||
|
- pacotes runtime/PVM quando presentes
|
||||||
|
|
||||||
|
## Alteracoes propostas
|
||||||
|
|
||||||
|
Opcao A: testes Java/reflection simples para imports, nomes de tipos e packages publicos.
|
||||||
|
|
||||||
|
Opcao B: ArchUnit caso a quantidade de regras e modulos justifique.
|
||||||
|
|
||||||
|
Recomendacao inicial: comecar com testes simples; reavaliar ArchUnit se as regras virarem frageis.
|
||||||
|
|
||||||
|
## Estrategia de implementacao
|
||||||
|
|
||||||
|
Definir allowlist de packages PBS, composition root e testes PBS. Escrever verificacoes independentes por dominio para falhas legiveis.
|
||||||
|
|
||||||
|
## Testes necessarios
|
||||||
|
|
||||||
|
- Backend/common nao importa `frontend.pbs`, `parser.pbs` ou `semantic.pbs`.
|
||||||
|
- IR comum nao expoe tipos PBS.
|
||||||
|
- Studio comum nao instancia servicos PBS fora da allowlist.
|
||||||
|
- Runtime nao usa nomenclatura ou semantica PBS.
|
||||||
|
|
||||||
|
## Criterios de aceitacao
|
||||||
|
|
||||||
|
- Regras rodam no build local.
|
||||||
|
- Falhas apontam arquivo/pacote responsavel.
|
||||||
|
- Excecoes autorizadas estao documentadas.
|
||||||
|
|
||||||
|
## Riscos
|
||||||
|
|
||||||
|
- Teste textual produzir falso positivo por docs ou fixtures.
|
||||||
|
- Criar barreira rigida antes de definir provider e lifecycle.
|
||||||
|
|
||||||
|
## Decisoes que devem ser registradas
|
||||||
|
|
||||||
|
- Ferramenta escolhida.
|
||||||
|
- Allowlist de packages.
|
||||||
|
- Ordem de introducao das regras.
|
||||||
|
|
||||||
@ -0,0 +1,77 @@
|
|||||||
|
---
|
||||||
|
id: AGD-0068
|
||||||
|
ticket: multi-frontend-avoid-premature-abstractions
|
||||||
|
title: Evitar abstracoes prematuras na preparacao multi-frontend
|
||||||
|
status: open
|
||||||
|
created: 2026-07-15
|
||||||
|
resolved:
|
||||||
|
decision:
|
||||||
|
tags: [compiler, compiler-general, studio, frontend, architecture, multi-frontend, simplicity]
|
||||||
|
---
|
||||||
|
|
||||||
|
# Agenda - Evitar abstracoes prematuras
|
||||||
|
|
||||||
|
## Objetivo
|
||||||
|
|
||||||
|
Domain owner: `compiler/general`, com impacto em `studio`.
|
||||||
|
|
||||||
|
Definir limites para a preparacao multi-frontend: remover acoplamento com baixo custo sem construir marketplace, hot reload, RPC, sandbox ou infraestrutura generica antes da necessidade real.
|
||||||
|
|
||||||
|
## Contexto atual
|
||||||
|
|
||||||
|
O PBS continuara sendo o unico frontend implementado no curto prazo. O objetivo e preparar contratos, fronteiras e testes de neutralidade, nao criar uma plataforma completa de plugins.
|
||||||
|
|
||||||
|
## Escopo
|
||||||
|
|
||||||
|
- Estabelecer principios para as agendas derivadas.
|
||||||
|
- Definir o que e explicitamente proibido nesta fase.
|
||||||
|
- Criar criterio para rejeitar abstracoes sem uso real.
|
||||||
|
|
||||||
|
## Fora de escopo
|
||||||
|
|
||||||
|
- Plugin marketplace.
|
||||||
|
- Carregamento dinamico de JARs.
|
||||||
|
- RPC, sockets, process supervisor ou version negotiation complexa.
|
||||||
|
- Service locator global.
|
||||||
|
|
||||||
|
## Arquivos e componentes a inspecionar
|
||||||
|
|
||||||
|
- `prometeu-compiler/prometeu-frontend-registry/...`
|
||||||
|
- `prometeu-app/src/main/java/p/studio/AppContainer.java`
|
||||||
|
- `prometeu-studio/src/main/java/p/studio/...`
|
||||||
|
- planos futuros derivados das discussions multi-frontend
|
||||||
|
|
||||||
|
## Alteracoes propostas
|
||||||
|
|
||||||
|
Opcao A: registrar esta decisao como guardrail transversal antes das demais.
|
||||||
|
|
||||||
|
Opcao B: deixar cada agenda repetir suas restricoes locais.
|
||||||
|
|
||||||
|
Recomendacao inicial: criar uma decisao curta e transversal apos discussao, para guiar provider, language services, synthetic frontend e testes arquiteturais.
|
||||||
|
|
||||||
|
## Estrategia de implementacao
|
||||||
|
|
||||||
|
Transformar o alinhamento em criterios de review: interface pequena, registro explicito, DI/composicao, records imutaveis e testes; rejeitar infra que nao seja exigida pelo PBS ou pelo frontend sintetico de teste.
|
||||||
|
|
||||||
|
## Testes necessarios
|
||||||
|
|
||||||
|
- Nao ha teste direto para simplicidade, mas plans devem incluir criterio de aceite contra reflection/scanning/RPC quando aplicavel.
|
||||||
|
- Testes arquiteturais podem proteger contra service locator global ou acoplamentos indevidos.
|
||||||
|
|
||||||
|
## Criterios de aceitacao
|
||||||
|
|
||||||
|
- Plans derivados nao introduzem infraestrutura de plugin antes da necessidade.
|
||||||
|
- Registro manual do PBS e suficiente.
|
||||||
|
- O frontend sintetico prova neutralidade sem virar plataforma externa.
|
||||||
|
|
||||||
|
## Riscos
|
||||||
|
|
||||||
|
- Usar "evitar abstracao" como desculpa para manter acoplamento PBS.
|
||||||
|
- Criar contratos tao pequenos que precisem ser quebrados imediatamente.
|
||||||
|
|
||||||
|
## Decisoes que devem ser registradas
|
||||||
|
|
||||||
|
- Guardrails obrigatorios para esta fase.
|
||||||
|
- Lista de mecanismos proibidos.
|
||||||
|
- Criterio para aceitar uma nova abstracao.
|
||||||
|
|
||||||
@ -15,10 +15,6 @@ This document defines the current contract between:
|
|||||||
Its purpose is to let compiler and runtime work in parallel without diverging on the most critical boundary:
|
Its purpose is to let compiler and runtime work in parallel without diverging on the most critical boundary:
|
||||||
how host-backed SDK calls become load-time-resolved numeric syscalls.
|
how host-backed SDK calls become load-time-resolved numeric syscalls.
|
||||||
|
|
||||||
PBS `declare host` / `[Host]` shells are compile-time delivery. The
|
|
||||||
loader-facing catalog is runtime-owned. This document MUST NOT publish syscall
|
|
||||||
IDs or `SyscallMeta`.
|
|
||||||
|
|
||||||
This document is intentionally narrower than a full PBX or VM specification.
|
This document is intentionally narrower than a full PBX or VM specification.
|
||||||
It focuses on loader behavior and the minimum artifact contract the loader must consume.
|
It focuses on loader behavior and the minimum artifact contract the loader must consume.
|
||||||
|
|
||||||
@ -48,20 +44,16 @@ This document does not define:
|
|||||||
|
|
||||||
This document follows two prior decisions:
|
This document follows two prior decisions:
|
||||||
|
|
||||||
1. Canonical host identity is defined by the runtime host registry as `(module, name, version)`.
|
1. Canonical host identity is defined by the hardware ABI as `(module, name, version)`.
|
||||||
2. User code does not declare host bindings directly; SDK/toolchain-controlled modules expose reserved `declare host` surfaces and the compiler lowers those usages into PBX host-binding metadata.
|
2. User code does not declare host bindings directly; SDK/toolchain-controlled modules expose reserved `declare host` surfaces and the compiler lowers those usages into PBX host-binding metadata.
|
||||||
|
|
||||||
PBS shells MUST repeat identities already published by the runtime registry
|
|
||||||
(`../runtime/docs/specs/runtime/16-host-abi-and-syscalls.md` and `SyscallMeta`).
|
|
||||||
They MUST NOT invent `(module, name, version)`.
|
|
||||||
|
|
||||||
This document therefore treats:
|
This document therefore treats:
|
||||||
|
|
||||||
- `declare host LowGfx { [Host(module = "gfx2d", name = "clear", version = 1)] fn clear(...); }`
|
- `declare host Gfx { fn draw_pixel(...); }`
|
||||||
|
|
||||||
as compile-time surface only, and treats:
|
as compile-time surface only, and treats:
|
||||||
|
|
||||||
- `("gfx2d", "clear", 1)`
|
- `("gfx", "draw_pixel", 1)`
|
||||||
|
|
||||||
as the normative runtime-facing identity.
|
as the normative runtime-facing identity.
|
||||||
|
|
||||||
@ -71,7 +63,7 @@ The host-binding pipeline is:
|
|||||||
|
|
||||||
1. User code imports SDK surfaces such as `Gfx` from `@sdk:gfx` and `Composer` from `@sdk:composer`.
|
1. User code imports SDK surfaces such as `Gfx` from `@sdk:gfx` and `Composer` from `@sdk:composer`.
|
||||||
2. The compiler resolves those surfaces against the selected stdlib line.
|
2. The compiler resolves those surfaces against the selected stdlib line.
|
||||||
3. The compiler maps each host-backed SDK member to a canonical identity `(module, name, version)` that already exists in the runtime host registry.
|
3. The compiler maps each host-backed SDK member to a canonical identity `(module, name, version)`.
|
||||||
4. The compiler emits those required canonical identities into the PBX `SYSC` table.
|
4. The compiler emits those required canonical identities into the PBX `SYSC` table.
|
||||||
5. The compiler emits pre-load host call sites as `HOSTCALL <sysc_index>`.
|
5. The compiler emits pre-load host call sites as `HOSTCALL <sysc_index>`.
|
||||||
6. At cartridge load time, the loader resolves `SYSC` entries against the host syscall registry.
|
6. At cartridge load time, the loader resolves `SYSC` entries against the host syscall registry.
|
||||||
@ -92,7 +84,7 @@ Every host binding is identified by the triple:
|
|||||||
|
|
||||||
Rules:
|
Rules:
|
||||||
|
|
||||||
- `module` is the canonical host subsystem namespace, such as `gfx2d` or `asset`.
|
- `module` is the canonical host subsystem namespace, such as `gfx` or `audio`.
|
||||||
- `name` is the canonical host operation name within that module.
|
- `name` is the canonical host operation name within that module.
|
||||||
- `version` is the canonical ABI version of that host operation.
|
- `version` is the canonical ABI version of that host operation.
|
||||||
- This identity is stable across source languages and SDK naming styles.
|
- This identity is stable across source languages and SDK naming styles.
|
||||||
@ -318,10 +310,7 @@ Rules:
|
|||||||
- the loader resolves only against this canonical registry,
|
- the loader resolves only against this canonical registry,
|
||||||
- unknown identities are load errors,
|
- unknown identities are load errors,
|
||||||
- successful resolution yields numeric syscall identifiers and associated metadata,
|
- successful resolution yields numeric syscall identifiers and associated metadata,
|
||||||
- the resolved metadata is authoritative for capability gating and later runtime verification,
|
- the resolved metadata is authoritative for capability gating and later runtime verification.
|
||||||
- PBS `declare host` / `[Host]` shells MUST repeat identities from this registry,
|
|
||||||
- PBS shells MUST NOT invent `(module, name, version)`,
|
|
||||||
- this specification MUST NOT publish the syscall catalog; runtime spec 16 and `SyscallMeta` do.
|
|
||||||
|
|
||||||
For the current asset runtime surface, the canonical registry entries include:
|
For the current asset runtime surface, the canonical registry entries include:
|
||||||
|
|
||||||
|
|||||||
@ -16,11 +16,7 @@ Its purpose is to make the stdlib:
|
|||||||
|
|
||||||
This document complements the normative language-level model in:
|
This document complements the normative language-level model in:
|
||||||
|
|
||||||
- [5. Manifest, Stdlib, and SDK Resolution Specification.md](5.%20Manifest%2C%20Stdlib%2C%20and%20SDK%20Resolution%20Specification.md)
|
- [5. Manifest, Stdlib, and SDK Resolution Specification.md](/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/studio/docs/specs/pbs/5.%20Manifest,%20Stdlib,%20and%20SDK%20Resolution%20Specification.md)
|
||||||
|
|
||||||
This document is PBS packaging. It MUST NOT define console ABI. Intrinsic
|
|
||||||
`final_id` values and host `SyscallMeta` remain runtime-owned. Physical stdlib
|
|
||||||
path MUST NOT imply VM-owned versus host-backed ownership.
|
|
||||||
|
|
||||||
## 2. Scope
|
## 2. Scope
|
||||||
|
|
||||||
@ -57,66 +53,52 @@ The recommended Studio layout is:
|
|||||||
```text
|
```text
|
||||||
prometeu-compiler/frontends/prometeu-frontend-pbs/
|
prometeu-compiler/frontends/prometeu-frontend-pbs/
|
||||||
src/main/resources/
|
src/main/resources/
|
||||||
<target>/
|
stdlib/
|
||||||
stdlib/
|
1/
|
||||||
1/
|
sdk/
|
||||||
core/
|
composer/
|
||||||
color/
|
main.pbs
|
||||||
main.pbs
|
mod.barrel
|
||||||
mod.barrel
|
gfx/
|
||||||
sdk/
|
main.pbs
|
||||||
asset/
|
mod.barrel
|
||||||
main.pbs
|
asset/
|
||||||
mod.barrel
|
main.pbs
|
||||||
composer/
|
mod.barrel
|
||||||
main.pbs
|
audio/
|
||||||
mod.barrel
|
main.pbs
|
||||||
gfx/
|
mod.barrel
|
||||||
main.pbs
|
core/
|
||||||
mod.barrel
|
math/
|
||||||
input/
|
main.pbs
|
||||||
main.pbs
|
mod.barrel
|
||||||
mod.barrel
|
|
||||||
log/
|
|
||||||
main.pbs
|
|
||||||
mod.barrel
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Interpretation:
|
Interpretation:
|
||||||
|
|
||||||
- `<target>` is the `AppMode` export name (`game` for the current line-1 environment),
|
- `stdlib/1` selects stdlib major line `1`,
|
||||||
- `game/stdlib/1` selects stdlib major line `1` for that target,
|
|
||||||
- `sdk` and `core` are reserved project spaces,
|
- `sdk` and `core` are reserved project spaces,
|
||||||
- current line `1` modules are `color`, `asset`, `composer`, `gfx`, `input`, and `log`,
|
- `composer`, `gfx`, `audio`, `math` are module paths within those reserved spaces,
|
||||||
- `main.pbs` and `mod.barrel` form the interface module contents.
|
- `main.pbs` and `mod.barrel` form the interface module contents.
|
||||||
|
|
||||||
Current line `1` MUST NOT be documented as shipping `audio` or `@core:math`.
|
|
||||||
Those names are not packaged in the current environment. `@sdk:input` is a
|
|
||||||
VM-owned builtin shell; its path does not make it host-backed.
|
|
||||||
|
|
||||||
## 5. Logical Mapping
|
## 5. Logical Mapping
|
||||||
|
|
||||||
The compiler must treat the physical layout as a logical stdlib environment.
|
The compiler must treat the physical layout as a logical stdlib environment.
|
||||||
|
|
||||||
Required mapping:
|
Required mapping:
|
||||||
|
|
||||||
- `<target>/stdlib/<N>/<space>/<module>` -> `@<space>:<module>`
|
- `stdlib/<N>/sdk/gfx` -> `@sdk:gfx`
|
||||||
|
- `stdlib/<N>/sdk/composer` -> `@sdk:composer`
|
||||||
Current line `1` (`game`) mapping:
|
- `stdlib/<N>/sdk/asset` -> `@sdk:asset`
|
||||||
|
- `stdlib/<N>/sdk/audio` -> `@sdk:audio`
|
||||||
- `game/stdlib/1/core/color` -> `@core:color`
|
- `stdlib/<N>/core/math` -> `@core:math`
|
||||||
- `game/stdlib/1/sdk/asset` -> `@sdk:asset`
|
- `stdlib/<N>/core/math/vector` -> `@core:math/vector`
|
||||||
- `game/stdlib/1/sdk/composer` -> `@sdk:composer`
|
|
||||||
- `game/stdlib/1/sdk/gfx` -> `@sdk:gfx`
|
|
||||||
- `game/stdlib/1/sdk/input` -> `@sdk:input`
|
|
||||||
- `game/stdlib/1/sdk/log` -> `@sdk:log`
|
|
||||||
|
|
||||||
Rules:
|
Rules:
|
||||||
|
|
||||||
- physical storage is an implementation detail,
|
- physical storage is an implementation detail,
|
||||||
- logical module identity is authoritative,
|
- logical module identity is authoritative,
|
||||||
- callers of the resolver should work with logical addresses such as `@sdk:gfx` and `@core:color`, not resource paths,
|
- callers of the resolver should work with logical addresses such as `@sdk:gfx` and `@sdk:composer`, not resource paths.
|
||||||
- physical path MUST NOT imply VM-owned versus host-backed ownership.
|
|
||||||
|
|
||||||
## 6. Module File Convention
|
## 6. Module File Convention
|
||||||
|
|
||||||
@ -168,8 +150,7 @@ Minimum operations:
|
|||||||
|
|
||||||
- `resolve(@sdk:gfx)`
|
- `resolve(@sdk:gfx)`
|
||||||
- `resolve(@sdk:composer)`
|
- `resolve(@sdk:composer)`
|
||||||
- `resolve(@sdk:input)`
|
- `resolve(@core:math/vector)`
|
||||||
- `resolve(@core:color)`
|
|
||||||
|
|
||||||
### 7.3 `StdlibModuleSource`
|
### 7.3 `StdlibModuleSource`
|
||||||
|
|
||||||
|
|||||||
@ -7,9 +7,6 @@ Applies to: normative stdlib-facing API surface, reserved stdlib project spaces,
|
|||||||
|
|
||||||
This document will define the normative user-facing standard-library surface for PBS.
|
This document will define the normative user-facing standard-library surface for PBS.
|
||||||
|
|
||||||
This document is PBS delivery. It does not own console ABI. Intrinsic
|
|
||||||
`final_id` values and host syscall metadata are runtime-owned.
|
|
||||||
|
|
||||||
## 2. Scope
|
## 2. Scope
|
||||||
|
|
||||||
This document is intended to define:
|
This document is intended to define:
|
||||||
@ -31,22 +28,15 @@ This document does not define:
|
|||||||
|
|
||||||
Normative precedence:
|
Normative precedence:
|
||||||
|
|
||||||
1. Runtime intrinsic catalog (`../runtime/docs/vm-arch/INTRINSICS.csv`; Studio mirror `docs/vm-arch/INTRINSICS.csv`)
|
1. `5. Manifest, Stdlib, and SDK Resolution Specification.md`
|
||||||
2. Runtime host ABI (`../runtime/docs/specs/runtime/16-host-abi-and-syscalls.md` and `SyscallMeta`)
|
2. `8. Stdlib Environment Packaging and Loading Specification.md`
|
||||||
3. `5. Manifest, Stdlib, and SDK Resolution Specification.md`
|
3. `6. VM-owned vs Host-backed.md`
|
||||||
4. `8. Stdlib Environment Packaging and Loading Specification.md`
|
4. `6.1. Intrinsics and Builtin Types Specification.md`
|
||||||
5. `6. VM-owned vs Host-backed.md`
|
5. `6.2. Host ABI Binding and Loader Resolution Specification.md`
|
||||||
6. `6.1. Intrinsics and Builtin Types Specification.md`
|
6. This document
|
||||||
7. `6.2. Host ABI Binding and Loader Resolution Specification.md`
|
|
||||||
8. This document
|
|
||||||
|
|
||||||
If a rule here conflicts with higher-precedence specs, it is invalid.
|
If a rule here conflicts with higher-precedence specs, it is invalid.
|
||||||
|
|
||||||
This document MUST NOT define numeric syscall identifiers, intrinsic `final_id`
|
|
||||||
values, or `SyscallMeta`. PBS `[Host]` and `[IntrinsicCall]` attributes MUST
|
|
||||||
repeat identities already published by those runtime catalogs. They MUST NOT
|
|
||||||
invent console ABI.
|
|
||||||
|
|
||||||
## 4. Normative Inputs
|
## 4. Normative Inputs
|
||||||
|
|
||||||
This document depends on, at minimum:
|
This document depends on, at minimum:
|
||||||
@ -67,9 +57,6 @@ The following inputs are already fixed elsewhere and must not be contradicted he
|
|||||||
- User code must import stdlib modules explicitly.
|
- User code must import stdlib modules explicitly.
|
||||||
- Canonical host identity comes from reserved host-binding metadata, not from source owner spelling.
|
- Canonical host identity comes from reserved host-binding metadata, not from source owner spelling.
|
||||||
- VM-owned builtin type, builtin constant, and intrinsic surfaces may be exposed through reserved stdlib shells without transferring semantic ownership away from the VM.
|
- VM-owned builtin type, builtin constant, and intrinsic surfaces may be exposed through reserved stdlib shells without transferring semantic ownership away from the VM.
|
||||||
- Console ABI authority is runtime-owned. PBS stdlib is delivery.
|
|
||||||
- Reserved project-space path (`@sdk:*` / `@core:*`) MUST NOT imply VM-owned versus host-backed ownership.
|
|
||||||
- Current stdlib line `1` ships a VM-owned builtin input shell at `@sdk:input`. That exception does not make `@sdk:*` the VM-owned space.
|
|
||||||
|
|
||||||
## 6. Initial Section Targets
|
## 6. Initial Section Targets
|
||||||
|
|
||||||
@ -91,10 +78,7 @@ The following items remain to be closed in future agenda discussion.
|
|||||||
- Whether `@core:*` is specified as language-adjacent utility surface or as ordinary stdlib contract.
|
- Whether `@core:*` is specified as language-adjacent utility surface or as ordinary stdlib contract.
|
||||||
- How stdlib API evolution is documented and conformance-tested.
|
- How stdlib API evolution is documented and conformance-tested.
|
||||||
- Whether some interface modules remain toolchain-private and outside user-facing stdlib surface.
|
- Whether some interface modules remain toolchain-private and outside user-facing stdlib surface.
|
||||||
|
- Whether builtin shells may appear in `@sdk:*` as well as `@core:*`, or whether `@sdk:*` should remain host-facing only by policy.
|
||||||
Settled by DEC-0048 and not reopened here:
|
|
||||||
|
|
||||||
- Builtin shells MAY appear in `@sdk:*` as well as `@core:*`. Path MUST NOT imply ownership. Current line `1` exception: `@sdk:input`.
|
|
||||||
|
|
||||||
## 8. Non-Goals
|
## 8. Non-Goals
|
||||||
|
|
||||||
@ -143,12 +127,6 @@ Rules:
|
|||||||
- but ownership remains governed by the VM-owned vs host-backed classification,
|
- but ownership remains governed by the VM-owned vs host-backed classification,
|
||||||
- and placing a builtin shell in stdlib does not make it host-backed.
|
- and placing a builtin shell in stdlib does not make it host-backed.
|
||||||
|
|
||||||
Current line `1` exception:
|
|
||||||
|
|
||||||
- `@sdk:input` exposes VM-owned builtin input types through `[BuiltinType]` and `[IntrinsicCall]`.
|
|
||||||
- that module is not host-backed.
|
|
||||||
- the `@sdk:*` preference for host-backed APIs still holds for new host modules.
|
|
||||||
|
|
||||||
## 11. Builtin Shell Surfaces
|
## 11. Builtin Shell Surfaces
|
||||||
|
|
||||||
Reserved stdlib modules may expose builtin declarations as compile-time-only
|
Reserved stdlib modules may expose builtin declarations as compile-time-only
|
||||||
@ -227,10 +205,6 @@ Their canonical runtime-facing identities still come from builtin metadata such
|
|||||||
as `BuiltinType(name="vec2", version=1)` and
|
as `BuiltinType(name="vec2", version=1)` and
|
||||||
`BuiltinConst(target="vec2", name="zero", version=1)`.
|
`BuiltinConst(target="vec2", name="zero", version=1)`.
|
||||||
|
|
||||||
Current stdlib line `1` ships `Color` at `@core:color`. The `@core:math` import
|
|
||||||
above is an identity illustration, not a claim that `@core:math` is packaged in
|
|
||||||
line `1`.
|
|
||||||
|
|
||||||
## 14. Deterministic Stdlib Surface Failures
|
## 14. Deterministic Stdlib Surface Failures
|
||||||
|
|
||||||
At minimum, a conforming implementation must reject:
|
At minimum, a conforming implementation must reject:
|
||||||
@ -240,15 +214,3 @@ At minimum, a conforming implementation must reject:
|
|||||||
3. a user-facing stdlib module that exports executable PBS bodies for builtin semantics,
|
3. a user-facing stdlib module that exports executable PBS bodies for builtin semantics,
|
||||||
4. a stdlib line that exposes conflicting canonical builtin identities through the same resolved environment,
|
4. a stdlib line that exposes conflicting canonical builtin identities through the same resolved environment,
|
||||||
5. a stdlib line that exposes conflicting canonical host identities through the same resolved environment.
|
5. a stdlib line that exposes conflicting canonical host identities through the same resolved environment.
|
||||||
|
|
||||||
## 15. Console ABI Non-Ownership
|
|
||||||
|
|
||||||
This specification MUST NOT:
|
|
||||||
|
|
||||||
1. define numeric syscall identifiers,
|
|
||||||
2. define intrinsic `final_id` values,
|
|
||||||
3. publish `SyscallMeta`,
|
|
||||||
4. or treat PBS `[Host]` / `[IntrinsicCall]` attributes as the ABI catalog.
|
|
||||||
|
|
||||||
PBS shells MUST repeat identities already published by the runtime catalogs
|
|
||||||
named in section 3.
|
|
||||||
|
|||||||
@ -210,4 +210,4 @@ This specification MUST NOT be read as authorizing:
|
|||||||
- extracting PBS linking;
|
- extracting PBS linking;
|
||||||
- or reopening lifecycle-assembly ownership.
|
- or reopening lifecycle-assembly ownership.
|
||||||
|
|
||||||
Platform validators MUST NOT depend on types from the PBS frontend module (`prometeu-frontend-pbs`). The package `p.studio.compiler.pbs` is not the complete boundary; facades shipped by that module remain PBS-owned. Platform validators MUST NOT discover roles from `__pbs.` prefixes.
|
Platform validators MUST NOT import `p.studio.compiler.pbs` and MUST NOT discover roles from `__pbs.` prefixes.
|
||||||
|
|||||||
@ -92,7 +92,7 @@ The declaration MUST represent, using ordered collections and typed ids:
|
|||||||
|
|
||||||
References MUST use `ModuleId`, `FileId`, `CallableId`, a typed role, and source attribution. The public shape MUST NOT expose maps, sets, callbacks, compiler services, or frontend-owned types.
|
References MUST use `ModuleId`, `FileId`, `CallableId`, a typed role, and source attribution. The public shape MUST NOT expose maps, sets, callbacks, compiler services, or frontend-owned types.
|
||||||
|
|
||||||
`AssembleLifecyclePipelineStage` MUST run after `FrontendPhasePipelineStage` and before `LowerToIRVMPipelineStage`. `LifecycleAssemblerService` is the only owner of derived lifecycle artifacts: module init, project-init wrapper, published frame wrapper, physical entrypoint, and hidden boot guard. Those artifacts MUST use deterministic neutral internal identities. Common code MUST NOT discover roles from `__pbs.*` prefixes or depend on types from the PBS frontend module (`prometeu-frontend-pbs`). The package `p.studio.compiler.pbs` is not the complete boundary.
|
`AssembleLifecyclePipelineStage` MUST run after `FrontendPhasePipelineStage` and before `LowerToIRVMPipelineStage`. `LifecycleAssemblerService` is the only owner of derived lifecycle artifacts: module init, project-init wrapper, published frame wrapper, physical entrypoint, and hidden boot guard. Those artifacts MUST use deterministic neutral internal identities. Common code MUST NOT discover roles from `__pbs.*` prefixes or depend on PBS packages.
|
||||||
|
|
||||||
The declaration MUST remain available on the assembled `IRBackend` as typed provenance. Downstream inspection MUST use roles, ids, and origins rather than synthetic names.
|
The declaration MUST remain available on the assembled `IRBackend` as typed provenance. Downstream inspection MUST use roles, ids, and origins rather than synthetic names.
|
||||||
|
|
||||||
@ -104,7 +104,7 @@ The common backend contract MUST NOT expose or require:
|
|||||||
2. PBS parser cursors, parse contexts, parse nodes, or token kinds,
|
2. PBS parser cursors, parse contexts, parse nodes, or token kinds,
|
||||||
3. PBS semantic validator internals,
|
3. PBS semantic validator internals,
|
||||||
4. PBS editorial or language-service objects,
|
4. PBS editorial or language-service objects,
|
||||||
5. or any type from the PBS frontend module (`prometeu-frontend-pbs`) or an equivalent language frontend module as part of the public backend handoff.
|
5. or any type under a language frontend package as part of the public backend handoff.
|
||||||
|
|
||||||
## 4.2 Serializable-by-Design Contract Shape
|
## 4.2 Serializable-by-Design Contract Shape
|
||||||
|
|
||||||
|
|||||||
@ -45,17 +45,17 @@ to concrete positive/negative test evidence and current status.
|
|||||||
| G19-11.3 | Platform diagnostics MUST use `COMMON_*` / `LOWER_IRVM_*` / `MARSHAL_*` and MUST copy origin/span when present. | `ValidationOwnershipSpecTest#spec19MustBeCompilerGeneralAndPublishValidationOwnership`; `LifecycleAssemblerServiceTest#assembleMustRejectMissingFrameRootWithoutRepair` | N/A | pass | Code families and span policy are normative in spec 19 section 11.1. |
|
| G19-11.3 | Platform diagnostics MUST use `COMMON_*` / `LOWER_IRVM_*` / `MARSHAL_*` and MUST copy origin/span when present. | `ValidationOwnershipSpecTest#spec19MustBeCompilerGeneralAndPublishValidationOwnership`; `LifecycleAssemblerServiceTest#assembleMustRejectMissingFrameRootWithoutRepair` | N/A | pass | Code families and span policy are normative in spec 19 section 11.1. |
|
||||||
| G19-11.4 | The same fact MAY exist as a language diagnostic and a platform diagnostic with distinct identities. | `ValidationOwnershipSpecTest#spec19MustBeCompilerGeneralAndPublishValidationOwnership` | N/A | pass | Dual reporting is required when a check reads both source and common contract. |
|
| G19-11.4 | The same fact MAY exist as a language diagnostic and a platform diagnostic with distinct identities. | `ValidationOwnershipSpecTest#spec19MustBeCompilerGeneralAndPublishValidationOwnership` | N/A | pass | Dual reporting is required when a check reads both source and common contract. |
|
||||||
| G19-11.5 | Host admission MUST split source attribute shape from canonical `IRReservedMetadata` identity without moving the PBS validator in this plan. | `ValidationOwnershipSpecTest#spec19MustBeCompilerGeneralAndPublishValidationOwnership` | N/A | pass | Classified as platform; validator remains in the PBS package. |
|
| G19-11.5 | Host admission MUST split source attribute shape from canonical `IRReservedMetadata` identity without moving the PBS validator in this plan. | `ValidationOwnershipSpecTest#spec19MustBeCompilerGeneralAndPublishValidationOwnership` | N/A | pass | Classified as platform; validator remains in the PBS package. |
|
||||||
| G19-11.6 | Platform validators MUST NOT depend on PBS frontend module types or match `__pbs.` prefixes. | `PbsModuleBoundaryArchTest#productionOutsideAllowlistMustNotDependOnPbsModuleTypes`; `CommonBackendPbsPrefixScanTest#commonLifecycleAndBackendMustNotDiscoverRolesFromPbsNamePrefixes` | N/A | pass | ArchUnit covers PBS module origin, including facades outside `p.studio.compiler.pbs`; source scan still rejects `__pbs.` in backend, lifecycle, and common pipeline stages. |
|
| G19-11.6 | Platform validators MUST NOT import PBS packages or match `__pbs.` prefixes. | `CommonBackendArchitectureTest#commonBackendMustNotImportPbsFrontendPackages`; `CommonBackendArchitectureTest#commonLifecycleAndBackendMustNotDiscoverRolesFromPbsNamePrefixes` | N/A | pass | Guard covers backend, lifecycle, and all common pipeline stages. |
|
||||||
| PBS12-11 | PBS diagnostics MUST NOT claim common structural lifecycle/IRVM failures as PBS required coverage. | `ValidationOwnershipSpecTest#pbsDiagnosticsMustNotClaimCommonStructuralFailures` | N/A | pass | PBS spec 12 points those failures at spec 19 section 11 and spec 20. |
|
| PBS12-11 | PBS diagnostics MUST NOT claim common structural lifecycle/IRVM failures as PBS required coverage. | `ValidationOwnershipSpecTest#pbsDiagnosticsMustNotClaimCommonStructuralFailures` | N/A | pass | PBS spec 12 points those failures at spec 19 section 11 and spec 20. |
|
||||||
| G20-4.1.1 | `IRBackend` MUST be the common frontend-to-backend executable handoff. | `LowerToIRVMServiceTest#lowerMustAcceptManuallyConstructedCommonIRBackend` | N/A | pass | Direct backend lowering from manually constructed common IRBackend proves PBS parser/frontend services are not required. |
|
| G20-4.1.1 | `IRBackend` MUST be the common frontend-to-backend executable handoff. | `LowerToIRVMServiceTest#lowerMustAcceptManuallyConstructedCommonIRBackend` | N/A | pass | Direct backend lowering from manually constructed common IRBackend proves PBS parser/frontend services are not required. |
|
||||||
| G20-4.1.2 | Common backend code MUST NOT depend on types from the PBS frontend module. | `PbsModuleBoundaryArchTest#productionOutsideAllowlistMustNotDependOnPbsModuleTypes`; `PbsModuleBoundaryArchTest#irBackendModelsMustNotDependOnPbsModuleTypes` | N/A | pass | ArchUnit rejects PBS-module origin types in common production code, including facades outside `p.studio.compiler.pbs`. |
|
| G20-4.1.2 | Common backend code MUST NOT depend on `p.studio.compiler.pbs`. | `CommonBackendArchitectureTest#commonBackendMustNotImportPbsFrontendPackages` | N/A | pass | Source-level architectural guard rejects PBS frontend imports in common backend packages. |
|
||||||
| G20-4.1.3 | Public `IRBackend` contract MUST NOT expose PBS AST, token, parser, semantic, or editorial types. | `IRBackendExecutableContractTest#publicIRBackendContractMustNotExposePbsTypes` | N/A | pass | Reflection guard covers public contract fields, constructors, methods, and record components. |
|
| G20-4.1.3 | Public `IRBackend` contract MUST NOT expose PBS AST, token, parser, semantic, or editorial types. | `IRBackendExecutableContractTest#publicIRBackendContractMustNotExposePbsTypes` | N/A | pass | Reflection guard covers public contract fields, constructors, methods, and record components. |
|
||||||
| G20-4.2.1 | Public `IRBackend` contract types MUST remain modelable as an acyclic, deterministic data graph. | `IRBackendExecutableContractTest#publicIRBackendContractMustExposeOnlySerializableShapes`; `IRBackendExecutableContractTest#aggregatorMustEmitDeterministicOrderedPublicContractShape` | N/A | pass | Covers public shape guardrails, generic type arguments, ordered aggregate emission, table remapping, and capability de-duplication order. |
|
| G20-4.2.1 | Public `IRBackend` contract types MUST remain modelable as an acyclic, deterministic data graph. | `IRBackendExecutableContractTest#publicIRBackendContractMustExposeOnlySerializableShapes`; `IRBackendExecutableContractTest#aggregatorMustEmitDeterministicOrderedPublicContractShape` | N/A | pass | Covers public shape guardrails, generic type arguments, ordered aggregate emission, table remapping, and capability de-duplication order. |
|
||||||
| G20-4.2.2 | Public `IRBackend` contract types MUST NOT expose callbacks, services, mutable/unordered collection contracts, frontend-owned objects, process-dependent lazy values, cyclic public references, or wire-format commitments. | `IRBackendExecutableContractTest#publicIRBackendContractMustExposeOnlySerializableShapes` | N/A | pass | Reflection guard covers public contract fields, constructors, methods, record components, and generic type arguments. |
|
| G20-4.2.2 | Public `IRBackend` contract types MUST NOT expose callbacks, services, mutable/unordered collection contracts, frontend-owned objects, process-dependent lazy values, cyclic public references, or wire-format commitments. | `IRBackendExecutableContractTest#publicIRBackendContractMustExposeOnlySerializableShapes` | N/A | pass | Reflection guard covers public contract fields, constructors, methods, record components, and generic type arguments. |
|
||||||
| G20-4.2.3 | Public `IRBackend` cross-object references MUST use explicit ids or stable symbolic keys. | `IRBackendExecutableContractTest#publicIRBackendContractAuditMustClassifyAllowedSupportTypes`; `IRBackendExecutableContractTest#publicIRBackendContractMustUseExplicitIdsOrStableKeysForKnownReferences` | N/A | pass | Current audit found no concrete public serialization leak requiring model correction. Existing `FileId`, `ModuleId`, `CallableId`, and `IntrinsicId` remain explicit table-scoped identifiers. |
|
| G20-4.2.3 | Public `IRBackend` cross-object references MUST use explicit ids or stable symbolic keys. | `IRBackendExecutableContractTest#publicIRBackendContractAuditMustClassifyAllowedSupportTypes`; `IRBackendExecutableContractTest#publicIRBackendContractMustUseExplicitIdsOrStableKeysForKnownReferences` | N/A | pass | Current audit found no concrete public serialization leak requiring model correction. Existing `FileId`, `ModuleId`, `CallableId`, and `IntrinsicId` remain explicit table-scoped identifiers. |
|
||||||
| G20-4.3.1 | Executable `IRBackend` MUST carry a typed, ordered, id-based `IRLifecycleDeclaration` as provenance. | `IRBackendExecutableContractTest#aggregatorMustRemapTypedLifecycleReferencesAndPreserveDeclaredModuleOrder`; `LifecycleAssemblerServiceTest#assembleMustMaterializeNeutralLifecycleArtifactsInDeclaredOrder` | `IRBackendExecutableContractTest#aggregatorMustOmitLifecycleDeclarationWhenNoFileContributesOne` | pass | Declaration uses `ReadOnlyList`, typed ids, roles, and source attribution; aggregator remaps ids with explicit module order. |
|
| G20-4.3.1 | Executable `IRBackend` MUST carry a typed, ordered, id-based `IRLifecycleDeclaration` as provenance. | `IRBackendExecutableContractTest#aggregatorMustRemapTypedLifecycleReferencesAndPreserveDeclaredModuleOrder`; `LifecycleAssemblerServiceTest#assembleMustMaterializeNeutralLifecycleArtifactsInDeclaredOrder` | `IRBackendExecutableContractTest#aggregatorMustOmitLifecycleDeclarationWhenNoFileContributesOne` | pass | Declaration uses `ReadOnlyList`, typed ids, roles, and source attribution; aggregator remaps ids with explicit module order. |
|
||||||
| G20-4.3.2 | Missing lifecycle declaration MUST mean a deliberately non-executable handoff and MUST NOT synthesize entrypoints. | `LifecycleAssemblerServiceTest#assembleMustNoOpWhenLifecycleDeclarationIsAbsent`; `AssembleLifecyclePipelineStageTest#runMustNoOpForDeliberatelyNonExecutableHandoff` | N/A | pass | Assembler and stage leave the backend unchanged when the declaration is absent. |
|
| G20-4.3.2 | Missing lifecycle declaration MUST mean a deliberately non-executable handoff and MUST NOT synthesize entrypoints. | `LifecycleAssemblerServiceTest#assembleMustNoOpWhenLifecycleDeclarationIsAbsent`; `AssembleLifecyclePipelineStageTest#runMustNoOpForDeliberatelyNonExecutableHandoff` | N/A | pass | Assembler and stage leave the backend unchanged when the declaration is absent. |
|
||||||
| G20-4.3.3 | Common lifecycle assembly MUST be the exclusive owner of derived artifacts and MUST use neutral identities. | `LifecycleAssemblerServiceTest#assembleMustMaterializeNeutralLifecycleArtifactsInDeclaredOrder`; `CommonBackendPbsPrefixScanTest#commonLifecycleAndBackendMustNotDiscoverRolesFromPbsNamePrefixes`; `PbsModuleBoundaryArchTest#productionOutsideAllowlistMustNotDependOnPbsModuleTypes` | `LifecycleAssemblerServiceTest#assembleMustRejectPreMaterializedDerivedArtifacts` | pass | Derived wrappers and boot guard are common-owned; ArchUnit rejects PBS-module types and the source scan rejects `__pbs.` prefix matching. |
|
| G20-4.3.3 | Common lifecycle assembly MUST be the exclusive owner of derived artifacts and MUST use neutral identities. | `LifecycleAssemblerServiceTest#assembleMustMaterializeNeutralLifecycleArtifactsInDeclaredOrder`; `CommonBackendArchitectureTest#commonLifecycleAndBackendMustNotDiscoverRolesFromPbsNamePrefixes` | `LifecycleAssemblerServiceTest#assembleMustRejectPreMaterializedDerivedArtifacts` | pass | Derived wrappers and boot guard are common-owned; architecture guard rejects PBS imports and `__pbs.` prefix matching. |
|
||||||
| G20-6.2 | `IRVM_EXT` MUST declare structural metadata (`pops/pushes/is_branch/is_terminator`). | `IRVMValidatorTest#validateMustApplyStructuralMetadataForCustomInternalExtension`; `IRVMValidatorTest#validateMustRejectCustomInternalExtensionWhenStructuralMetadataUnderflowsStack`; `IRVMOp` record contract (`pops/pushes/branch/terminator/internal`) | N/A | pass | Dedicated extension fixtures now assert structural metadata is consumed by validation behavior. |
|
| G20-6.2 | `IRVM_EXT` MUST declare structural metadata (`pops/pushes/is_branch/is_terminator`). | `IRVMValidatorTest#validateMustApplyStructuralMetadataForCustomInternalExtension`; `IRVMValidatorTest#validateMustRejectCustomInternalExtensionWhenStructuralMetadataUnderflowsStack`; `IRVMOp` record contract (`pops/pushes/branch/terminator/internal`) | N/A | pass | Dedicated extension fixtures now assert structural metadata is consumed by validation behavior. |
|
||||||
| G20-6.3 | `IRVM_EXT` MUST be eliminable before bytecode emission. | `OptimizeIRVMServiceTest#optimizeDefaultPassesMustEliminateUnreachableInternalExtensionBeforeEmission` | `EmitBytecodePipelineStageTest#runMustFailWhenInternalOpcodesRemain`; `EmitBytecodePipelineStageTest#runMustFailWhenInternalOpcodesRemainEvenWithNonEmptyEmissionPlan`; `IRVMValidatorTest#validateMustRejectInternalOpcodeWhenConfigured` | pass | Optimizer elimination path and emit-stage hard rejection path are both covered. |
|
| G20-6.3 | `IRVM_EXT` MUST be eliminable before bytecode emission. | `OptimizeIRVMServiceTest#optimizeDefaultPassesMustEliminateUnreachableInternalExtensionBeforeEmission` | `EmitBytecodePipelineStageTest#runMustFailWhenInternalOpcodesRemain`; `EmitBytecodePipelineStageTest#runMustFailWhenInternalOpcodesRemainEvenWithNonEmptyEmissionPlan`; `IRVMValidatorTest#validateMustRejectInternalOpcodeWhenConfigured` | pass | Optimizer elimination path and emit-stage hard rejection path are both covered. |
|
||||||
| G20-6.4 | IRVM MUST preserve per-function slot and identity headers. | `IRVMProgramTest#constructorMustRejectModuleAndEmissionPlanMismatch` | `IRVMProgramTest#constructorMustRejectModuleAndEmissionPlanMismatch` | pass | Header mismatch is rejected deterministically. |
|
| G20-6.4 | IRVM MUST preserve per-function slot and identity headers. | `IRVMProgramTest#constructorMustRejectModuleAndEmissionPlanMismatch` | `IRVMProgramTest#constructorMustRejectModuleAndEmissionPlanMismatch` | pass | Header mismatch is rejected deterministically. |
|
||||||
@ -90,7 +90,6 @@ to concrete positive/negative test evidence and current status.
|
|||||||
| G23-6.3 | `build` MUST extend `compile` only with terminal artifact persistence. | `MainProjectPipelineIntegrationTest#buildShouldWriteProgramBytecode`; `BuilderPipelinePublicSurfaceTest#buildResultMustExposeArtifactPathAndCompilePayload` | N/A | pass | Coverage asserts that `build` retains the compile payload and writes the filesystem artifact path expected by callers. |
|
| G23-6.3 | `build` MUST extend `compile` only with terminal artifact persistence. | `MainProjectPipelineIntegrationTest#buildShouldWriteProgramBytecode`; `BuilderPipelinePublicSurfaceTest#buildResultMustExposeArtifactPathAndCompilePayload` | N/A | pass | Coverage asserts that `build` retains the compile payload and writes the filesystem artifact path expected by callers. |
|
||||||
| G23-7.1 | `AnalysisSnapshot` MUST expose the minimum shared analysis contract. | `MainProjectPipelineIntegrationTest#analyzeShouldNotWriteProgramBytecode`; `BuilderPipelinePublicSurfaceTest#analysisSnapshotMustExposeMinimumSharedContract` | N/A | pass | Both executable and structural contract checks now cover the shared minimum analysis payload. |
|
| G23-7.1 | `AnalysisSnapshot` MUST expose the minimum shared analysis contract. | `MainProjectPipelineIntegrationTest#analyzeShouldNotWriteProgramBytecode`; `BuilderPipelinePublicSurfaceTest#analysisSnapshotMustExposeMinimumSharedContract` | N/A | pass | Both executable and structural contract checks now cover the shared minimum analysis payload. |
|
||||||
| G23-8.1 | Caller-specific configs/contexts MUST NOT redefine canonical stage semantics. | N/A | N/A | missing | Requires explicit multi-entrypoint composition tests once non-filesystem contexts are implemented. |
|
| G23-8.1 | Caller-specific configs/contexts MUST NOT redefine canonical stage semantics. | N/A | N/A | missing | Requires explicit multi-entrypoint composition tests once non-filesystem contexts are implemented. |
|
||||||
| G23-8.3 | A compile-only `FrontendProvider` registered by `languageId` MUST traverse `compile()` to verified bytecode without PBS, `.pbs` sources, or PBS stdlib. | `SyntheticFrontendPipelineTest#compileMustEmitVerifiedBytecodeWithoutPbs` | `FrontendRegistryServiceTest#unregisterMustRefuseToRemoveDefaultPbs` | pass | Synthetic `synth` provider is test-only; common pipeline must not require PBS types, PBS sources, or PBS stdlib. |
|
|
||||||
| G23-9.1 | Legacy public `run` MUST be removed as the normative entrypoint and filesystem-default behavior MUST be expressed through `build`. | `BuilderPipelinePublicSurfaceTest#publicServiceSurfaceMustExposeExplicitEntrypointsAndNoPublicRun`; `MainProjectPipelineIntegrationTest#buildShouldWriteProgramBytecode` | N/A | partial | Public service coverage now proves `run` is no longer public and `build` is the filesystem artifact path, but the CLI composition path is not yet exercised by a dedicated automated test. |
|
| G23-9.1 | Legacy public `run` MUST be removed as the normative entrypoint and filesystem-default behavior MUST be expressed through `build`. | `BuilderPipelinePublicSurfaceTest#publicServiceSurfaceMustExposeExplicitEntrypointsAndNoPublicRun`; `MainProjectPipelineIntegrationTest#buildShouldWriteProgramBytecode` | N/A | partial | Public service coverage now proves `run` is no longer public and `build` is the filesystem artifact path, but the CLI composition path is not yet exercised by a dedicated automated test. |
|
||||||
| PBS13-12.0 | PBS executable lowering MUST emit `IRBackend` satisfying frontend handoff obligations before common backend lowering. | `IRBackendExecutableContractTest` suite; `PBSFrontendPhaseServiceTest#shouldSynthesizePositiveTopic19FixtureAcrossFileInitProjectInitAndFrame` | `LowerToIRVMServiceTest#lowerMustRejectWhenSyntheticWrapperEntrypointIsMissing`; `LowerToIRVMServiceTest#lowerMustRejectWhenHiddenBootGuardIsMissing`; `LowerToIRVMServiceTest#lowerMustRejectWhenSyntheticCallableOriginIsMissing` | pass | Row group `PBS13-12.x` verifies PBS emission into the common handoff; common backend ownership is covered by G20 rows. |
|
| PBS13-12.0 | PBS executable lowering MUST emit `IRBackend` satisfying frontend handoff obligations before common backend lowering. | `IRBackendExecutableContractTest` suite; `PBSFrontendPhaseServiceTest#shouldSynthesizePositiveTopic19FixtureAcrossFileInitProjectInitAndFrame` | `LowerToIRVMServiceTest#lowerMustRejectWhenSyntheticWrapperEntrypointIsMissing`; `LowerToIRVMServiceTest#lowerMustRejectWhenHiddenBootGuardIsMissing`; `LowerToIRVMServiceTest#lowerMustRejectWhenSyntheticCallableOriginIsMissing` | pass | Row group `PBS13-12.x` verifies PBS emission into the common handoff; common backend ownership is covered by G20 rows. |
|
||||||
| PBS13-12.7 | PBS executable lowering MUST emit a typed lifecycle declaration and MUST NOT assemble derived wrappers. | `PBSFrontendPhaseServiceTest#shouldSynthesizePositiveTopic19FixtureAcrossFileInitProjectInitAndFrame`; `PbsFrontendCompilerTest#shouldExposeGlobalsAndTypedLifecycleDeclarationInBackendFile` | N/A | pass | Frontend tests assert declaration roles and the absence of module init, published wrapper, and boot guard. |
|
| PBS13-12.7 | PBS executable lowering MUST emit a typed lifecycle declaration and MUST NOT assemble derived wrappers. | `PBSFrontendPhaseServiceTest#shouldSynthesizePositiveTopic19FixtureAcrossFileInitProjectInitAndFrame`; `PbsFrontendCompilerTest#shouldExposeGlobalsAndTypedLifecycleDeclarationInBackendFile` | N/A | pass | Frontend tests assert declaration roles and the absence of module init, published wrapper, and boot guard. |
|
||||||
|
|||||||
@ -284,10 +284,6 @@ Provider registration MUST be explicit in v1. The registry contract MUST NOT use
|
|||||||
|
|
||||||
PBS is the only initial real provider for this contract. PBS MAY be registered by an application composition root, but PBS MUST NOT become an exclusive semantic owner of the shared compiler pipeline.
|
PBS is the only initial real provider for this contract. PBS MAY be registered by an application composition root, but PBS MUST NOT become an exclusive semantic owner of the shared compiler pipeline.
|
||||||
|
|
||||||
A compile-only `FrontendProvider` registered by `languageId` MUST be a valid participant of `analyze`, `compile`, and `build`. The shared pipeline MUST NOT require PBS frontend types, `.pbs` or `.barrel` sources, or PBS stdlib in order to emit verified bytecode. Test-only frontends MAY exist solely as fixtures. They MUST NOT be product languages, MUST NOT be registered by default bootstrap or Studio composition, and MUST NOT be discovered by plugin scanning, classpath scanning, or external JAR loading.
|
|
||||||
|
|
||||||
The frontend registry MUST expose explicit `register` and `unregister` operations. `unregister` MUST refuse to remove the default PBS provider. Lookup of an unknown `languageId` MUST fail explicitly. `unregister` of an unknown `languageId` MUST be a no-op.
|
|
||||||
|
|
||||||
## 9. Public Surface Rule
|
## 9. Public Surface Rule
|
||||||
|
|
||||||
The shared compiler public surface MUST expose explicit entrypoints equivalent in meaning to:
|
The shared compiler public surface MUST expose explicit entrypoints equivalent in meaning to:
|
||||||
|
|||||||
@ -5,7 +5,6 @@ jackson = "2.18.2"
|
|||||||
jacoco = "0.8.12"
|
jacoco = "0.8.12"
|
||||||
lombok = "1.18.32"
|
lombok = "1.18.32"
|
||||||
junit-jupiter = "5.12.1"
|
junit-jupiter = "5.12.1"
|
||||||
archunit = "1.4.2"
|
|
||||||
slf4j = "2.0.7"
|
slf4j = "2.0.7"
|
||||||
lsp4j = "1.0.0"
|
lsp4j = "1.0.0"
|
||||||
|
|
||||||
@ -20,7 +19,6 @@ apache-commons-collections = { group = "org.apache.commons", name = "commons-col
|
|||||||
jacoco-core = { group = "org.jacoco", name = "org.jacoco.core", version.ref = "jacoco" }
|
jacoco-core = { group = "org.jacoco", name = "org.jacoco.core", version.ref = "jacoco" }
|
||||||
lombok = { group = "org.projectlombok", name = "lombok", version.ref = "lombok" }
|
lombok = { group = "org.projectlombok", name = "lombok", version.ref = "lombok" }
|
||||||
junit-jupiter = { group = "org.junit.jupiter", name = "junit-jupiter", version.ref = "junit-jupiter" }
|
junit-jupiter = { group = "org.junit.jupiter", name = "junit-jupiter", version.ref = "junit-jupiter" }
|
||||||
archunit-junit5 = { group = "com.tngtech.archunit", name = "archunit-junit5", version.ref = "archunit" }
|
|
||||||
slf4j-api = { group = "org.slf4j", name = "slf4j-api", version.ref = "slf4j" }
|
slf4j-api = { group = "org.slf4j", name = "slf4j-api", version.ref = "slf4j" }
|
||||||
slf4j-simple = { group = "org.slf4j", name = "slf4j-simple", version.ref = "slf4j" }
|
slf4j-simple = { group = "org.slf4j", name = "slf4j-simple", version.ref = "slf4j" }
|
||||||
lsp4j = { group = "org.eclipse.lsp4j", name = "org.eclipse.lsp4j", version.ref = "lsp4j" }
|
lsp4j = { group = "org.eclipse.lsp4j", name = "org.eclipse.lsp4j", version.ref = "lsp4j" }
|
||||||
|
|||||||
@ -7,6 +7,7 @@ dependencies {
|
|||||||
implementation(project(":prometeu-infra"))
|
implementation(project(":prometeu-infra"))
|
||||||
implementation(project(":prometeu-lsp:prometeu-lsp-api"))
|
implementation(project(":prometeu-lsp:prometeu-lsp-api"))
|
||||||
implementation(project(":prometeu-lsp:prometeu-lsp-v1"))
|
implementation(project(":prometeu-lsp:prometeu-lsp-v1"))
|
||||||
|
implementation(project(":prometeu-compiler:frontends:prometeu-frontend-pbs"))
|
||||||
implementation(project(":prometeu-compiler:prometeu-frontend-registry"))
|
implementation(project(":prometeu-compiler:prometeu-frontend-registry"))
|
||||||
implementation(project(":prometeu-packer:prometeu-packer-api"))
|
implementation(project(":prometeu-packer:prometeu-packer-api"))
|
||||||
implementation(project(":prometeu-packer:prometeu-packer-v1"))
|
implementation(project(":prometeu-packer:prometeu-packer-v1"))
|
||||||
|
|||||||
@ -1,23 +0,0 @@
|
|||||||
plugins {
|
|
||||||
id("gradle.java-library-conventions")
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
testImplementation(libs.archunit.junit5)
|
|
||||||
|
|
||||||
testImplementation(project(":prometeu-compiler:frontends:prometeu-frontend-pbs"))
|
|
||||||
testImplementation(project(":prometeu-compiler:prometeu-frontend-registry"))
|
|
||||||
testImplementation(project(":prometeu-compiler:prometeu-compiler-core"))
|
|
||||||
testImplementation(project(":prometeu-compiler:prometeu-frontend-api"))
|
|
||||||
testImplementation(project(":prometeu-compiler:prometeu-build-pipeline"))
|
|
||||||
testImplementation(project(":prometeu-compiler:prometeu-deps"))
|
|
||||||
testImplementation(project(":prometeu-infra"))
|
|
||||||
testImplementation(project(":prometeu-lsp:prometeu-lsp-api"))
|
|
||||||
testImplementation(project(":prometeu-lsp:prometeu-lsp-v1"))
|
|
||||||
testImplementation(project(":prometeu-studio"))
|
|
||||||
testImplementation(project(":prometeu-app"))
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.named<JacocoReport>("jacocoTestReport") {
|
|
||||||
enabled = false
|
|
||||||
}
|
|
||||||
@ -1,63 +0,0 @@
|
|||||||
package p.studio.architecture;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
|
||||||
|
|
||||||
class CommonBackendPbsPrefixScanTest {
|
|
||||||
private static final String COMPILER_SOURCE_ROOT =
|
|
||||||
"prometeu-compiler/prometeu-build-pipeline/src/main/java/p/studio/compiler";
|
|
||||||
private static final List<String> GUARDED_RELATIVE_ROOTS = List.of(
|
|
||||||
"backend",
|
|
||||||
"lifecycle",
|
|
||||||
"workspaces/stages");
|
|
||||||
private static final String FORBIDDEN_PBS_PREFIX = "__pbs.";
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void commonLifecycleAndBackendMustNotDiscoverRolesFromPbsNamePrefixes() throws IOException {
|
|
||||||
final var violations = new ArrayList<String>();
|
|
||||||
final var repoRoot = locateRepoRoot();
|
|
||||||
final var compilerRoot = repoRoot.resolve(COMPILER_SOURCE_ROOT);
|
|
||||||
for (final var relativeRoot : GUARDED_RELATIVE_ROOTS) {
|
|
||||||
final var root = compilerRoot.resolve(relativeRoot);
|
|
||||||
if (!Files.exists(root)) {
|
|
||||||
fail("guarded source root is missing: " + root);
|
|
||||||
}
|
|
||||||
try (final var paths = Files.walk(root)) {
|
|
||||||
paths.filter(path -> path.toString().endsWith(".java")).forEach(path -> {
|
|
||||||
try {
|
|
||||||
if (Files.readString(path).contains(FORBIDDEN_PBS_PREFIX)) {
|
|
||||||
violations.add(repoRoot.relativize(path).toString());
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new IllegalStateException("failed to read source file: " + path, e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assertTrue(
|
|
||||||
violations.isEmpty(),
|
|
||||||
"common lifecycle/backend code must not inspect __pbs. prefixes: " + violations);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Path locateRepoRoot() {
|
|
||||||
var cursor = Path.of(System.getProperty("user.dir")).toAbsolutePath().normalize();
|
|
||||||
while (cursor != null) {
|
|
||||||
final var hasDocs = Files.isDirectory(cursor.resolve("docs/specs/compiler"));
|
|
||||||
final var hasCompiler = Files.isDirectory(cursor.resolve("prometeu-compiler"));
|
|
||||||
if (hasDocs && hasCompiler) {
|
|
||||||
return cursor;
|
|
||||||
}
|
|
||||||
cursor = cursor.getParent();
|
|
||||||
}
|
|
||||||
fail("could not locate repository root from working directory");
|
|
||||||
throw new IllegalStateException("unreachable");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
package p.studio.architecture;
|
|
||||||
|
|
||||||
import com.tngtech.archunit.base.DescribedPredicate;
|
|
||||||
import com.tngtech.archunit.core.domain.JavaClass;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
final class DescribedPredicates {
|
|
||||||
private DescribedPredicates() {
|
|
||||||
}
|
|
||||||
|
|
||||||
static DescribedPredicate<JavaClass> notBelongingTo(final Class<?>... allowed) {
|
|
||||||
final Set<String> allowedNames = Arrays.stream(allowed)
|
|
||||||
.map(Class::getName)
|
|
||||||
.collect(Collectors.toUnmodifiableSet());
|
|
||||||
return DescribedPredicate.describe(
|
|
||||||
"do not belong to " + allowedNames,
|
|
||||||
javaClass -> !allowedNames.contains(javaClass.getName()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,85 +0,0 @@
|
|||||||
package p.studio.architecture;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
|
||||||
|
|
||||||
class PbsGradleDependencyAllowlistTest {
|
|
||||||
private static final Pattern PBS_PROJECT_DEP = Pattern.compile(
|
|
||||||
"(\\w+)\\(\\s*project\\(\\s*\"" + Pattern.quote(PbsModuleOrigins.PBS_GRADLE_PATH) + "\"\\s*\\)");
|
|
||||||
private static final Map<String, Set<String>> ALLOWED_CONFIGURATIONS = Map.of(
|
|
||||||
":prometeu-compiler:prometeu-frontend-registry", Set.of("implementation", "api"),
|
|
||||||
":prometeu-architecture-tests", Set.of("testImplementation"));
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void onlyAllowlistedProjectsMayDependOnThePbsFrontendModule() throws IOException {
|
|
||||||
final var repoRoot = locateRepoRoot();
|
|
||||||
final var violations = new ArrayList<String>();
|
|
||||||
|
|
||||||
try (final var paths = Files.walk(repoRoot)) {
|
|
||||||
paths.filter(path -> path.getFileName().toString().equals("build.gradle.kts"))
|
|
||||||
.filter(path -> !path.toString().contains("/buildSrc/"))
|
|
||||||
.filter(path -> !path.toString().contains("/build/"))
|
|
||||||
.forEach(path -> collectViolations(repoRoot, path, violations));
|
|
||||||
}
|
|
||||||
|
|
||||||
assertTrue(violations.isEmpty(), "PBS Gradle project dependency allowlist violated: " + violations);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void collectViolations(
|
|
||||||
final Path repoRoot,
|
|
||||||
final Path buildFile,
|
|
||||||
final ArrayList<String> violations) {
|
|
||||||
final var projectPath = toProjectPath(repoRoot, buildFile);
|
|
||||||
if (PbsModuleOrigins.PBS_GRADLE_PATH.equals(projectPath)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final String content;
|
|
||||||
try {
|
|
||||||
content = Files.readString(buildFile);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new IllegalStateException("failed to read " + buildFile, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
final var matcher = PBS_PROJECT_DEP.matcher(content);
|
|
||||||
while (matcher.find()) {
|
|
||||||
final var configuration = matcher.group(1);
|
|
||||||
final var allowed = ALLOWED_CONFIGURATIONS.getOrDefault(projectPath, Set.of());
|
|
||||||
if (!allowed.contains(configuration)) {
|
|
||||||
violations.add(projectPath + " " + configuration + " " + PbsModuleOrigins.PBS_GRADLE_PATH);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String toProjectPath(final Path repoRoot, final Path buildFile) {
|
|
||||||
final var relative = repoRoot.relativize(buildFile.getParent()).toString().replace('\\', '/');
|
|
||||||
if (relative.isEmpty() || ".".equals(relative)) {
|
|
||||||
return ":";
|
|
||||||
}
|
|
||||||
return ":" + relative.replace('/', ':');
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Path locateRepoRoot() {
|
|
||||||
var cursor = Path.of(System.getProperty("user.dir")).toAbsolutePath().normalize();
|
|
||||||
while (cursor != null) {
|
|
||||||
final var hasDocs = Files.isDirectory(cursor.resolve("docs/specs/compiler"));
|
|
||||||
final var hasCompiler = Files.isDirectory(cursor.resolve("prometeu-compiler"));
|
|
||||||
if (hasDocs && hasCompiler) {
|
|
||||||
return cursor;
|
|
||||||
}
|
|
||||||
cursor = cursor.getParent();
|
|
||||||
}
|
|
||||||
fail("could not locate repository root from working directory");
|
|
||||||
throw new IllegalStateException("unreachable");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,43 +0,0 @@
|
|||||||
package p.studio.architecture;
|
|
||||||
|
|
||||||
import com.tngtech.archunit.core.importer.ImportOption;
|
|
||||||
import com.tngtech.archunit.junit.AnalyzeClasses;
|
|
||||||
import com.tngtech.archunit.junit.ArchTest;
|
|
||||||
import com.tngtech.archunit.lang.ArchRule;
|
|
||||||
import p.studio.compiler.PBSDefinitions;
|
|
||||||
import p.studio.compiler.PBSFrontendProvider;
|
|
||||||
|
|
||||||
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
|
|
||||||
import static p.studio.architecture.PbsModuleOrigins.fromFrontendApiModule;
|
|
||||||
import static p.studio.architecture.PbsModuleOrigins.fromPbsModule;
|
|
||||||
import static p.studio.architecture.PbsModuleOrigins.fromRegistryModule;
|
|
||||||
|
|
||||||
@AnalyzeClasses(packages = "p.studio", importOptions = ImportOption.DoNotIncludeTests.class)
|
|
||||||
class PbsModuleBoundaryArchTest {
|
|
||||||
|
|
||||||
@ArchTest
|
|
||||||
static final ArchRule productionOutsideAllowlistMustNotDependOnPbsModuleTypes = noClasses()
|
|
||||||
.that(fromPbsModule().negate())
|
|
||||||
.and(fromRegistryModule().negate())
|
|
||||||
.should()
|
|
||||||
.dependOnClassesThat(fromPbsModule())
|
|
||||||
.because("DEC-0050: only prometeu-frontend-pbs and prometeu-frontend-registry may depend on PBS module types");
|
|
||||||
|
|
||||||
@ArchTest
|
|
||||||
static final ArchRule registryMustOnlyDependOnPbsProviderFacade = noClasses()
|
|
||||||
.that(fromRegistryModule())
|
|
||||||
.should()
|
|
||||||
.dependOnClassesThat(
|
|
||||||
fromPbsModule()
|
|
||||||
.and(DescribedPredicates.notBelongingTo(PBSFrontendProvider.class, PBSDefinitions.class)))
|
|
||||||
.because("DEC-0050: registry may depend only on PBSFrontendProvider and PBSDefinitions");
|
|
||||||
|
|
||||||
@ArchTest
|
|
||||||
static final ArchRule irBackendModelsMustNotDependOnPbsModuleTypes = noClasses()
|
|
||||||
.that(fromFrontendApiModule())
|
|
||||||
.and()
|
|
||||||
.resideInAPackage("p.studio.compiler.models..")
|
|
||||||
.should()
|
|
||||||
.dependOnClassesThat(fromPbsModule())
|
|
||||||
.because("DEC-0050: public IRBackend contract types must not depend on PBS module types");
|
|
||||||
}
|
|
||||||
@ -1,36 +0,0 @@
|
|||||||
package p.studio.architecture;
|
|
||||||
|
|
||||||
import com.tngtech.archunit.core.importer.ClassFileImporter;
|
|
||||||
import com.tngtech.archunit.core.importer.ImportOption;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
|
||||||
|
|
||||||
class PbsModuleClasspathTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void importerMustSeePbsAndRegistryModuleOrigins() {
|
|
||||||
final var classes = new ClassFileImporter()
|
|
||||||
.withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
|
|
||||||
.importPackages("p.studio");
|
|
||||||
|
|
||||||
final var pbsSample = classes.stream()
|
|
||||||
.filter(PbsModuleOrigins::isPbsModule)
|
|
||||||
.findFirst();
|
|
||||||
final var registrySample = classes.stream()
|
|
||||||
.filter(PbsModuleOrigins::isRegistryModule)
|
|
||||||
.findFirst();
|
|
||||||
|
|
||||||
if (pbsSample.isEmpty() || registrySample.isEmpty()) {
|
|
||||||
final var uris = classes.stream()
|
|
||||||
.limit(20)
|
|
||||||
.map(javaClass -> javaClass.getName() + " -> " + PbsModuleOrigins.sourceUri(javaClass))
|
|
||||||
.toList();
|
|
||||||
fail("PBS/registry module origins were not visible to ArchUnit. sample URIs: " + uris);
|
|
||||||
}
|
|
||||||
|
|
||||||
assertTrue(pbsSample.isPresent());
|
|
||||||
assertTrue(registrySample.isPresent());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,60 +0,0 @@
|
|||||||
package p.studio.architecture;
|
|
||||||
|
|
||||||
import com.tngtech.archunit.base.DescribedPredicate;
|
|
||||||
import com.tngtech.archunit.core.domain.JavaClass;
|
|
||||||
|
|
||||||
final class PbsModuleOrigins {
|
|
||||||
static final String PBS_GRADLE_PATH = ":prometeu-compiler:frontends:prometeu-frontend-pbs";
|
|
||||||
|
|
||||||
private PbsModuleOrigins() {
|
|
||||||
}
|
|
||||||
|
|
||||||
static boolean isPbsModule(final JavaClass javaClass) {
|
|
||||||
return uriContains(javaClass, "/prometeu-frontend-pbs/")
|
|
||||||
|| uriContains(javaClass, "prometeu-frontend-pbs.jar");
|
|
||||||
}
|
|
||||||
|
|
||||||
static boolean isRegistryModule(final JavaClass javaClass) {
|
|
||||||
return uriContains(javaClass, "/prometeu-frontend-registry/")
|
|
||||||
|| uriContains(javaClass, "prometeu-frontend-registry.jar");
|
|
||||||
}
|
|
||||||
|
|
||||||
static boolean isFrontendApiModule(final JavaClass javaClass) {
|
|
||||||
return uriContains(javaClass, "/prometeu-frontend-api/")
|
|
||||||
|| uriContains(javaClass, "prometeu-frontend-api.jar");
|
|
||||||
}
|
|
||||||
|
|
||||||
static DescribedPredicate<JavaClass> fromPbsModule() {
|
|
||||||
return DescribedPredicate.describe(
|
|
||||||
"originate from the PBS frontend module",
|
|
||||||
PbsModuleOrigins::isPbsModule);
|
|
||||||
}
|
|
||||||
|
|
||||||
static DescribedPredicate<JavaClass> fromRegistryModule() {
|
|
||||||
return DescribedPredicate.describe(
|
|
||||||
"originate from the frontend registry module",
|
|
||||||
PbsModuleOrigins::isRegistryModule);
|
|
||||||
}
|
|
||||||
|
|
||||||
static DescribedPredicate<JavaClass> fromFrontendApiModule() {
|
|
||||||
return DescribedPredicate.describe(
|
|
||||||
"originate from the frontend-api module",
|
|
||||||
PbsModuleOrigins::isFrontendApiModule);
|
|
||||||
}
|
|
||||||
|
|
||||||
static String sourceUri(final JavaClass javaClass) {
|
|
||||||
return javaClass.getSource()
|
|
||||||
.map(source -> normalize(source.getUri().toString()))
|
|
||||||
.orElse("<no source>");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean uriContains(final JavaClass javaClass, final String fragment) {
|
|
||||||
return javaClass.getSource()
|
|
||||||
.map(source -> normalize(source.getUri().toString()).contains(fragment))
|
|
||||||
.orElse(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String normalize(final String uri) {
|
|
||||||
return uri.replace('\\', '/');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,99 +0,0 @@
|
|||||||
package p.studio.compiler.integration;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.junit.jupiter.api.io.TempDir;
|
|
||||||
import p.studio.compiler.FrontendRegistryService;
|
|
||||||
import p.studio.compiler.messages.BuilderPipelineConfig;
|
|
||||||
import p.studio.compiler.models.BuilderPipelineContext;
|
|
||||||
import p.studio.compiler.models.IRBackendReader;
|
|
||||||
import p.studio.compiler.models.IRHiddenGlobalKind;
|
|
||||||
import p.studio.compiler.synth.SyntheticFrontendProvider;
|
|
||||||
import p.studio.compiler.workspaces.BuilderPipelineService;
|
|
||||||
import p.studio.utilities.logs.LogAggregator;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
|
|
||||||
class SyntheticFrontendPipelineTest {
|
|
||||||
|
|
||||||
@TempDir
|
|
||||||
Path projectRoot;
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void compileMustEmitVerifiedBytecodeWithoutPbs() throws IOException {
|
|
||||||
writeSyntheticProject();
|
|
||||||
final var provider = new SyntheticFrontendProvider();
|
|
||||||
FrontendRegistryService.register(provider);
|
|
||||||
try {
|
|
||||||
final var context = BuilderPipelineContext.fromConfig(
|
|
||||||
new BuilderPipelineConfig(false, projectRoot.toString()));
|
|
||||||
final var result = BuilderPipelineService.INSTANCE.compile(context, LogAggregator.empty());
|
|
||||||
|
|
||||||
assertTrue(provider.syntheticCompiler().invoked(), "synthetic compiler must be the effective frontend");
|
|
||||||
assertEquals(
|
|
||||||
SyntheticFrontendProvider.LANGUAGE_ID,
|
|
||||||
result.analysisSnapshot().frontendSpec().getLanguageId());
|
|
||||||
assertFalse("pbs".equals(result.analysisSnapshot().frontendSpec().getLanguageId()));
|
|
||||||
assertTrue(provider.languageService().isEmpty());
|
|
||||||
assertTrue(
|
|
||||||
result.diagnostics().stream().noneMatch(issue -> issue.isError()),
|
|
||||||
result.diagnostics().toString());
|
|
||||||
assertNotNull(result.bytecodeModule());
|
|
||||||
assertNotNull(result.bytecodeBytes());
|
|
||||||
assertTrue(result.bytecodeBytes().length > 0);
|
|
||||||
|
|
||||||
final var backend = result.analysisSnapshot().irBackend();
|
|
||||||
assertEquals("__prometeu.lifecycle.frame_wrapper$m0", backend.getEntryPointCallableName());
|
|
||||||
assertTrue(backend.getGlobals().stream().anyMatch(global ->
|
|
||||||
global.hiddenKind() == IRHiddenGlobalKind.BOOT_GUARD
|
|
||||||
&& "__prometeu.lifecycle.boot_guard$m0".equals(global.name())));
|
|
||||||
assertNoPbsNames(backend);
|
|
||||||
assertTrue(noPbsSources(projectRoot));
|
|
||||||
} finally {
|
|
||||||
FrontendRegistryService.unregister(SyntheticFrontendProvider.LANGUAGE_ID);
|
|
||||||
assertEquals(1, FrontendRegistryService.listProviders().size());
|
|
||||||
assertEquals(
|
|
||||||
"pbs",
|
|
||||||
FrontendRegistryService.listProviders().getFirst().specification().getLanguageId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeSyntheticProject() throws IOException {
|
|
||||||
Files.writeString(projectRoot.resolve("prometeu.json"), """
|
|
||||||
{
|
|
||||||
"name": "synth-fixture",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"language": "synth",
|
|
||||||
"stdlib": "1",
|
|
||||||
"target": "Game",
|
|
||||||
"dependencies": []
|
|
||||||
}
|
|
||||||
""");
|
|
||||||
Files.createDirectory(projectRoot.resolve("src"));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertNoPbsNames(final IRBackendReader backend) {
|
|
||||||
assertFalse(backend.getEntryPointCallableName().contains("__pbs."));
|
|
||||||
assertTrue(backend.getExecutableFunctions().stream()
|
|
||||||
.noneMatch(function -> function.callableName().contains("__pbs.")));
|
|
||||||
assertTrue(backend.getSyntheticFunctions().stream()
|
|
||||||
.noneMatch(function -> function.callableName().contains("__pbs.")));
|
|
||||||
assertTrue(backend.getGlobals().stream()
|
|
||||||
.noneMatch(global -> global.name().contains("__pbs.")));
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean noPbsSources(final Path root) throws IOException {
|
|
||||||
try (final var files = Files.walk(root)) {
|
|
||||||
return files
|
|
||||||
.filter(Files::isRegularFile)
|
|
||||||
.map(path -> path.getFileName().toString())
|
|
||||||
.noneMatch(name -> name.endsWith(".pbs") || name.endsWith(".barrel"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -95,8 +95,7 @@ class BackendConformanceMatrixSpecTest {
|
|||||||
"PBS13-12.7",
|
"PBS13-12.7",
|
||||||
"PBS13-12.8",
|
"PBS13-12.8",
|
||||||
"PBS13-12.9",
|
"PBS13-12.9",
|
||||||
"G23-5.2",
|
"G23-5.2");
|
||||||
"G23-8.3");
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void matrixMustExistAndContainRequiredRequirementRows() throws IOException {
|
void matrixMustExistAndContainRequiredRequirementRows() throws IOException {
|
||||||
|
|||||||
@ -0,0 +1,96 @@
|
|||||||
|
package p.studio.compiler.specs;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
|
|
||||||
|
class CommonBackendArchitectureTest {
|
||||||
|
private static final String COMPILER_SOURCE_ROOT =
|
||||||
|
"prometeu-compiler/prometeu-build-pipeline/src/main/java/p/studio/compiler";
|
||||||
|
private static final List<String> GUARDED_RELATIVE_ROOTS = List.of(
|
||||||
|
"backend",
|
||||||
|
"lifecycle",
|
||||||
|
"workspaces/stages");
|
||||||
|
private static final String FORBIDDEN_PBS_PACKAGE = "p.studio.compiler.pbs";
|
||||||
|
private static final String FORBIDDEN_PBS_PREFIX = "__pbs.";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void commonBackendMustNotImportPbsFrontendPackages() throws IOException {
|
||||||
|
final var violations = new ArrayList<String>();
|
||||||
|
walkGuardedSources(path -> assertNoPbsImport(path, violations));
|
||||||
|
assertTrue(
|
||||||
|
violations.isEmpty(),
|
||||||
|
"common backend must not import PBS frontend packages: " + violations);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void commonLifecycleAndBackendMustNotDiscoverRolesFromPbsNamePrefixes() throws IOException {
|
||||||
|
final var violations = new ArrayList<String>();
|
||||||
|
walkGuardedSources(path -> assertNoPbsPrefixMatching(path, violations));
|
||||||
|
assertTrue(
|
||||||
|
violations.isEmpty(),
|
||||||
|
"common lifecycle/backend code must not inspect __pbs. prefixes: " + violations);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void walkGuardedSources(final java.util.function.Consumer<Path> consumer) throws IOException {
|
||||||
|
final var compilerRoot = locateRepoRoot().resolve(COMPILER_SOURCE_ROOT);
|
||||||
|
for (final var relativeRoot : GUARDED_RELATIVE_ROOTS) {
|
||||||
|
final var root = compilerRoot.resolve(relativeRoot);
|
||||||
|
if (Files.isRegularFile(root)) {
|
||||||
|
consumer.accept(root);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try (final var paths = Files.walk(root)) {
|
||||||
|
paths.filter(path -> path.toString().endsWith(".java")).forEach(consumer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertNoPbsImport(
|
||||||
|
final Path path,
|
||||||
|
final ArrayList<String> violations) {
|
||||||
|
try {
|
||||||
|
final var content = Files.readString(path);
|
||||||
|
if (content.contains("import " + FORBIDDEN_PBS_PACKAGE)
|
||||||
|
|| content.contains("import static " + FORBIDDEN_PBS_PACKAGE)) {
|
||||||
|
violations.add(locateRepoRoot().relativize(path).toString());
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new IllegalStateException("failed to read source file: " + path, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertNoPbsPrefixMatching(
|
||||||
|
final Path path,
|
||||||
|
final ArrayList<String> violations) {
|
||||||
|
try {
|
||||||
|
final var content = Files.readString(path);
|
||||||
|
if (content.contains(FORBIDDEN_PBS_PREFIX)) {
|
||||||
|
violations.add(locateRepoRoot().relativize(path).toString());
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new IllegalStateException("failed to read source file: " + path, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Path locateRepoRoot() {
|
||||||
|
var cursor = Path.of(System.getProperty("user.dir")).toAbsolutePath().normalize();
|
||||||
|
while (cursor != null) {
|
||||||
|
final var hasDocs = Files.isDirectory(cursor.resolve("docs/specs/compiler"));
|
||||||
|
final var hasCompiler = Files.isDirectory(cursor.resolve("prometeu-compiler"));
|
||||||
|
if (hasDocs && hasCompiler) {
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
cursor = cursor.getParent();
|
||||||
|
}
|
||||||
|
fail("could not locate repository root from working directory");
|
||||||
|
throw new IllegalStateException("unreachable");
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,109 +0,0 @@
|
|||||||
package p.studio.compiler.specs;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
|
||||||
|
|
||||||
class ConsoleAbiAuthoritySpecTest {
|
|
||||||
private static final String SPEC_18 =
|
|
||||||
"docs/specs/compiler/18. Standard Library Surface Specification.md";
|
|
||||||
private static final String PBS_SPEC_8 =
|
|
||||||
"docs/specs/compiler-languages/pbs/8. Stdlib Environment Packaging and Loading Specification.md";
|
|
||||||
private static final String PBS_SPEC_6_2 =
|
|
||||||
"docs/specs/compiler-languages/pbs/6.2. Host ABI Binding and Loader Resolution Specification.md";
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void spec18MustTreatStdlibAsDeliveryAndMustNotOwnConsoleAbi() throws IOException {
|
|
||||||
final var content = Files.readString(locateRepoRoot().resolve(SPEC_18));
|
|
||||||
|
|
||||||
assertTrue(
|
|
||||||
content.contains("This document is PBS delivery. It does not own console ABI."),
|
|
||||||
"spec 18 must state that PBS stdlib is delivery, not console ABI");
|
|
||||||
assertTrue(
|
|
||||||
content.contains("This document MUST NOT define numeric syscall identifiers, intrinsic `final_id`"),
|
|
||||||
"spec 18 must forbid defining syscall IDs and intrinsic final IDs");
|
|
||||||
assertTrue(
|
|
||||||
content.contains("or `SyscallMeta`"),
|
|
||||||
"spec 18 must forbid publishing SyscallMeta");
|
|
||||||
assertTrue(
|
|
||||||
content.contains("## 15. Console ABI Non-Ownership"),
|
|
||||||
"spec 18 must contain Console ABI Non-Ownership");
|
|
||||||
assertTrue(
|
|
||||||
content.contains("Reserved project-space path (`@sdk:*` / `@core:*`) MUST NOT imply VM-owned versus host-backed ownership."),
|
|
||||||
"spec 18 must state that @sdk/@core paths do not imply ownership");
|
|
||||||
assertTrue(
|
|
||||||
content.contains("Current stdlib line `1` ships a VM-owned builtin input shell at `@sdk:input`."),
|
|
||||||
"spec 18 must record @sdk:input as the current builtin exception");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void spec8MustDocumentCurrentGameStdlibLayout() throws IOException {
|
|
||||||
final var content = Files.readString(locateRepoRoot().resolve(PBS_SPEC_8));
|
|
||||||
final var layoutFence = extractFirstTextFence(content);
|
|
||||||
|
|
||||||
assertTrue(content.contains("game/stdlib/1"), "spec 8 must document game/stdlib/1");
|
|
||||||
assertTrue(content.contains("game/stdlib/1/core/color"), "spec 8 must map @core:color");
|
|
||||||
assertTrue(content.contains("game/stdlib/1/sdk/input"), "spec 8 must map @sdk:input");
|
|
||||||
assertTrue(content.contains("game/stdlib/1/sdk/log"), "spec 8 must map @sdk:log");
|
|
||||||
assertTrue(
|
|
||||||
content.contains("Physical stdlib\npath MUST NOT imply VM-owned versus host-backed ownership."),
|
|
||||||
"spec 8 must state that packaging path does not imply ownership");
|
|
||||||
assertTrue(layoutFence.contains("core/\n color/"), "layout fence must include core/color");
|
|
||||||
assertTrue(layoutFence.contains("input/"), "layout fence must include sdk/input");
|
|
||||||
assertTrue(layoutFence.contains("log/"), "layout fence must include sdk/log");
|
|
||||||
assertFalse(layoutFence.contains("audio/"), "layout fence must not ship audio as a current module");
|
|
||||||
assertFalse(layoutFence.contains("math/"), "layout fence must not ship core/math as a current module");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void spec62MustRequirePbsHostShellsToRepeatRuntimeRegistry() throws IOException {
|
|
||||||
final var content = Files.readString(locateRepoRoot().resolve(PBS_SPEC_6_2));
|
|
||||||
|
|
||||||
assertTrue(
|
|
||||||
content.contains("PBS shells MUST repeat identities already published by the runtime registry"),
|
|
||||||
"spec 6.2 must require PBS shells to repeat the runtime registry");
|
|
||||||
assertTrue(
|
|
||||||
content.contains("They MUST NOT invent `(module, name, version)`."),
|
|
||||||
"spec 6.2 must forbid inventing canonical host identity");
|
|
||||||
assertTrue(
|
|
||||||
content.contains("This document MUST NOT publish syscall\nIDs or `SyscallMeta`."),
|
|
||||||
"spec 6.2 must not publish the syscall catalog");
|
|
||||||
assertTrue(
|
|
||||||
content.contains("(\"gfx2d\", \"clear\", 1)"),
|
|
||||||
"spec 6.2 authority example must use a current runtime identity");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String extractFirstTextFence(final String content) {
|
|
||||||
final var startToken = "```text";
|
|
||||||
final var start = content.indexOf(startToken);
|
|
||||||
if (start < 0) {
|
|
||||||
fail("spec 8 must contain a text layout fence");
|
|
||||||
}
|
|
||||||
final var fenceStart = start + startToken.length();
|
|
||||||
final var end = content.indexOf("```", fenceStart);
|
|
||||||
if (end < 0) {
|
|
||||||
fail("spec 8 layout fence is unclosed");
|
|
||||||
}
|
|
||||||
return content.substring(fenceStart, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Path locateRepoRoot() {
|
|
||||||
var cursor = Path.of(System.getProperty("user.dir")).toAbsolutePath().normalize();
|
|
||||||
while (cursor != null) {
|
|
||||||
final var hasDocs = Files.isDirectory(cursor.resolve("docs/specs/compiler"));
|
|
||||||
final var hasCompiler = Files.isDirectory(cursor.resolve("prometeu-compiler"));
|
|
||||||
if (hasDocs && hasCompiler) {
|
|
||||||
return cursor;
|
|
||||||
}
|
|
||||||
cursor = cursor.getParent();
|
|
||||||
}
|
|
||||||
fail("could not locate repository root from working directory");
|
|
||||||
throw new IllegalStateException("unreachable");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -11,11 +11,93 @@ import p.studio.compiler.source.diagnostics.DiagnosticSink;
|
|||||||
import p.studio.utilities.logs.LogAggregator;
|
import p.studio.utilities.logs.LogAggregator;
|
||||||
import p.studio.utilities.structures.ReadOnlySet;
|
import p.studio.utilities.structures.ReadOnlySet;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
|
|
||||||
class FrontendProviderBoundaryTest {
|
class FrontendProviderBoundaryTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void commonModulesMustNotInstantiatePbsFrontendPhaseServiceDirectly() throws IOException {
|
||||||
|
final var repoRoot = findRepoRoot(Path.of("").toAbsolutePath().normalize());
|
||||||
|
final var commonSourceRoots = List.of(
|
||||||
|
repoRoot.resolve("prometeu-compiler/prometeu-build-pipeline/src/main/java"),
|
||||||
|
repoRoot.resolve("prometeu-compiler/prometeu-deps/src/main/java"),
|
||||||
|
repoRoot.resolve("prometeu-studio/src/main/java"),
|
||||||
|
repoRoot.resolve("prometeu-app/src/main/java"));
|
||||||
|
|
||||||
|
for (final var sourceRoot : commonSourceRoots) {
|
||||||
|
if (!Files.exists(sourceRoot)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try (final var files = Files.walk(sourceRoot)) {
|
||||||
|
final var violations = files
|
||||||
|
.filter(path -> path.toString().endsWith(".java"))
|
||||||
|
.filter(path -> contains(path, "new PBSFrontendPhaseService("))
|
||||||
|
.toList();
|
||||||
|
if (!violations.isEmpty()) {
|
||||||
|
fail("common modules must resolve frontend compiler behavior through FrontendProvider: " + violations);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void commonModulesMustNotInstantiatePbsEditorialSupportServiceDirectly() throws IOException {
|
||||||
|
final var repoRoot = findRepoRoot(Path.of("").toAbsolutePath().normalize());
|
||||||
|
final var sourceRoots = List.of(
|
||||||
|
repoRoot.resolve("prometeu-compiler/prometeu-build-pipeline/src/main/java"),
|
||||||
|
repoRoot.resolve("prometeu-compiler/prometeu-deps/src/main/java"),
|
||||||
|
repoRoot.resolve("prometeu-lsp/prometeu-lsp-v1/src/main/java"),
|
||||||
|
repoRoot.resolve("prometeu-studio/src/main/java"),
|
||||||
|
repoRoot.resolve("prometeu-app/src/main/java"));
|
||||||
|
|
||||||
|
for (final var sourceRoot : sourceRoots) {
|
||||||
|
if (!Files.exists(sourceRoot)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try (final var files = Files.walk(sourceRoot)) {
|
||||||
|
final var violations = files
|
||||||
|
.filter(path -> path.toString().endsWith(".java"))
|
||||||
|
.filter(path -> contains(path, "new PbsEditorialSupportService("))
|
||||||
|
.toList();
|
||||||
|
if (!violations.isEmpty()) {
|
||||||
|
fail("common modules must resolve PBS editor behavior through FrontendProvider.languageService(): " + violations);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void commonLspMustNotImportPbsImplementationPackages() throws IOException {
|
||||||
|
final var repoRoot = findRepoRoot(Path.of("").toAbsolutePath().normalize());
|
||||||
|
final var sourceRoot = repoRoot.resolve("prometeu-lsp/prometeu-lsp-v1/src/main/java");
|
||||||
|
final var prohibitedNeedles = List.of(
|
||||||
|
"p.studio.compiler.PBSFrontendLanguageService",
|
||||||
|
"p.studio.compiler.services.PBSFrontendPhaseService",
|
||||||
|
"p.studio.compiler.pbs",
|
||||||
|
"PbsAst",
|
||||||
|
"PbsEditorial");
|
||||||
|
|
||||||
|
try (final var files = Files.walk(sourceRoot)) {
|
||||||
|
final var violations = files
|
||||||
|
.filter(path -> path.toString().endsWith(".java"))
|
||||||
|
.filter(path -> prohibitedNeedles.stream().anyMatch(needle -> contains(path, needle)))
|
||||||
|
.toList();
|
||||||
|
if (!violations.isEmpty()) {
|
||||||
|
fail("common LSP code must consume generic frontend language-service contracts instead of PBS implementation packages: "
|
||||||
|
+ violations);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void compileOnlyFrontendProviderMayOmitLanguageService() {
|
void compileOnlyFrontendProviderMayOmitLanguageService() {
|
||||||
final FrontendProvider provider = new CompileOnlyFrontendProvider();
|
final FrontendProvider provider = new CompileOnlyFrontendProvider();
|
||||||
@ -28,6 +110,26 @@ class FrontendProviderBoundaryTest {
|
|||||||
BuildingIssueSink.empty()));
|
BuildingIssueSink.empty()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean contains(final Path path, final String needle) {
|
||||||
|
try {
|
||||||
|
return Files.readString(path).contains(needle);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new IllegalStateException("failed to read " + path, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Path findRepoRoot(final Path start) {
|
||||||
|
var current = start;
|
||||||
|
while (current != null) {
|
||||||
|
if (Files.exists(current.resolve("settings.gradle.kts"))) {
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
current = current.getParent();
|
||||||
|
}
|
||||||
|
fail("unable to locate repository root from " + start);
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
private static final class CompileOnlyFrontendProvider implements FrontendProvider {
|
private static final class CompileOnlyFrontendProvider implements FrontendProvider {
|
||||||
private final FrontendSpec specification = FrontendSpec.builder()
|
private final FrontendSpec specification = FrontendSpec.builder()
|
||||||
.languageId("compile-only")
|
.languageId("compile-only")
|
||||||
|
|||||||
@ -43,11 +43,8 @@ class ValidationOwnershipSpecTest {
|
|||||||
content.contains("Canonical host-binding identity"),
|
content.contains("Canonical host-binding identity"),
|
||||||
"spec 19 matrix must include the host-admission split");
|
"spec 19 matrix must include the host-admission split");
|
||||||
assertTrue(
|
assertTrue(
|
||||||
content.contains("MUST NOT depend on types from the PBS frontend module"),
|
content.contains("MUST NOT import `p.studio.compiler.pbs`"),
|
||||||
"spec 19 must forbid PBS frontend module types in platform validators");
|
"spec 19 must forbid PBS imports in platform validators");
|
||||||
assertTrue(
|
|
||||||
content.contains("`p.studio.compiler.pbs` is not the complete boundary"),
|
|
||||||
"spec 19 must not treat package p.studio.compiler.pbs as the complete PBS boundary");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@ -1,81 +0,0 @@
|
|||||||
package p.studio.compiler.synth;
|
|
||||||
|
|
||||||
import p.studio.compiler.messages.BuildingIssueSink;
|
|
||||||
import p.studio.compiler.messages.FrontendPhaseContext;
|
|
||||||
import p.studio.compiler.models.IRBackend;
|
|
||||||
import p.studio.compiler.models.IRBackendExecutableFunction;
|
|
||||||
import p.studio.compiler.models.IRLifecycleCallableReference;
|
|
||||||
import p.studio.compiler.models.IRLifecycleCallableRole;
|
|
||||||
import p.studio.compiler.models.IRLifecycleDeclaration;
|
|
||||||
import p.studio.compiler.models.IRLifecycleModuleDeclaration;
|
|
||||||
import p.studio.compiler.services.FrontendPhaseService;
|
|
||||||
import p.studio.compiler.source.Span;
|
|
||||||
import p.studio.compiler.source.diagnostics.DiagnosticSink;
|
|
||||||
import p.studio.compiler.source.identifiers.CallableId;
|
|
||||||
import p.studio.compiler.source.identifiers.FileId;
|
|
||||||
import p.studio.compiler.source.identifiers.ModuleId;
|
|
||||||
import p.studio.compiler.source.tables.CallableSignatureRef;
|
|
||||||
import p.studio.compiler.source.tables.ModuleReference;
|
|
||||||
import p.studio.utilities.logs.LogAggregator;
|
|
||||||
import p.studio.utilities.structures.ReadOnlyList;
|
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
|
|
||||||
public final class SyntheticFrontendPhaseService implements FrontendPhaseService {
|
|
||||||
private final AtomicBoolean invoked = new AtomicBoolean();
|
|
||||||
|
|
||||||
public boolean invoked() {
|
|
||||||
return invoked.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IRBackend compile(
|
|
||||||
final FrontendPhaseContext request,
|
|
||||||
final DiagnosticSink diagnostics,
|
|
||||||
final LogAggregator logs,
|
|
||||||
final BuildingIssueSink issues) {
|
|
||||||
invoked.set(true);
|
|
||||||
|
|
||||||
final var moduleId = new ModuleId(0);
|
|
||||||
final var fileId = new FileId(0);
|
|
||||||
final var callableId = new CallableId(0);
|
|
||||||
final var span = new Span(fileId, 0, 1);
|
|
||||||
final var frame = new IRBackendExecutableFunction(
|
|
||||||
fileId,
|
|
||||||
moduleId,
|
|
||||||
"frame",
|
|
||||||
callableId,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
ReadOnlyList.from(new IRBackendExecutableFunction.Instruction(
|
|
||||||
IRBackendExecutableFunction.InstructionKind.RET,
|
|
||||||
"",
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
span)),
|
|
||||||
span);
|
|
||||||
final var frameRoot = new IRLifecycleCallableReference(
|
|
||||||
moduleId,
|
|
||||||
fileId,
|
|
||||||
callableId,
|
|
||||||
IRLifecycleCallableRole.FRAME_ROOT,
|
|
||||||
span);
|
|
||||||
|
|
||||||
return IRBackend.builder()
|
|
||||||
.entryPointCallableName("frame")
|
|
||||||
.entryPointModuleId(moduleId)
|
|
||||||
.modulePool(ReadOnlyList.from(new ModuleReference("synth", ReadOnlyList.from("main"))))
|
|
||||||
.callableSignatures(ReadOnlyList.from(
|
|
||||||
new CallableSignatureRef(moduleId, "frame", 0, "() -> unit")))
|
|
||||||
.executableFunctions(ReadOnlyList.from(frame))
|
|
||||||
.lifecycleDeclaration(new IRLifecycleDeclaration(
|
|
||||||
ReadOnlyList.from(new IRLifecycleModuleDeclaration(moduleId, ReadOnlyList.empty())),
|
|
||||||
null,
|
|
||||||
frameRoot))
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
package p.studio.compiler.synth;
|
|
||||||
|
|
||||||
import p.studio.compiler.models.FrontendSpec;
|
|
||||||
import p.studio.compiler.services.FrontendPhaseService;
|
|
||||||
import p.studio.compiler.services.FrontendProvider;
|
|
||||||
import p.studio.utilities.structures.ReadOnlySet;
|
|
||||||
|
|
||||||
public final class SyntheticFrontendProvider implements FrontendProvider {
|
|
||||||
public static final String LANGUAGE_ID = "synth";
|
|
||||||
|
|
||||||
private final FrontendSpec specification = FrontendSpec.builder()
|
|
||||||
.languageId(LANGUAGE_ID)
|
|
||||||
.allowedExtensions(ReadOnlySet.from("synth"))
|
|
||||||
.sourceRoots(ReadOnlySet.from("src"))
|
|
||||||
.build();
|
|
||||||
private final SyntheticFrontendPhaseService compiler = new SyntheticFrontendPhaseService();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public FrontendSpec specification() {
|
|
||||||
return specification;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public FrontendPhaseService compiler() {
|
|
||||||
return compiler;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SyntheticFrontendPhaseService syntheticCompiler() {
|
|
||||||
return compiler;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -62,7 +62,7 @@ public class FrontendRegistryService {
|
|||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void register(final FrontendProvider provider) {
|
static void register(final FrontendProvider provider) {
|
||||||
final var languageId = provider.specification().getLanguageId();
|
final var languageId = provider.specification().getLanguageId();
|
||||||
if (FRONTEND_PROVIDERS.containsKey(languageId)) {
|
if (FRONTEND_PROVIDERS.containsKey(languageId)) {
|
||||||
throw new IllegalArgumentException("Duplicate frontend languageId: " + languageId);
|
throw new IllegalArgumentException("Duplicate frontend languageId: " + languageId);
|
||||||
@ -71,16 +71,6 @@ public class FrontendRegistryService {
|
|||||||
FRONTEND_PROVIDERS.put(languageId, provider);
|
FRONTEND_PROVIDERS.put(languageId, provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void unregister(final String languageId) {
|
|
||||||
if (languageId == null || languageId.isBlank()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (PBSDefinitions.PBS.getLanguageId().equals(languageId)) {
|
|
||||||
throw new IllegalArgumentException("Cannot unregister the default PBS frontend: " + languageId);
|
|
||||||
}
|
|
||||||
FRONTEND_PROVIDERS.remove(languageId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void registerIfAbsent(final FrontendProvider provider) {
|
private static void registerIfAbsent(final FrontendProvider provider) {
|
||||||
FRONTEND_PROVIDERS.putIfAbsent(provider.specification().getLanguageId(), provider);
|
FRONTEND_PROVIDERS.putIfAbsent(provider.specification().getLanguageId(), provider);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,15 +1,6 @@
|
|||||||
package p.studio.compiler;
|
package p.studio.compiler;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import p.studio.compiler.messages.BuildingIssueSink;
|
|
||||||
import p.studio.compiler.messages.FrontendPhaseContext;
|
|
||||||
import p.studio.compiler.models.FrontendSpec;
|
|
||||||
import p.studio.compiler.models.IRBackend;
|
|
||||||
import p.studio.compiler.services.FrontendPhaseService;
|
|
||||||
import p.studio.compiler.services.FrontendProvider;
|
|
||||||
import p.studio.compiler.source.diagnostics.DiagnosticSink;
|
|
||||||
import p.studio.utilities.logs.LogAggregator;
|
|
||||||
import p.studio.utilities.structures.ReadOnlySet;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||||
@ -50,89 +41,4 @@ class FrontendRegistryServiceTest {
|
|||||||
assertEquals(1, providers.size());
|
assertEquals(1, providers.size());
|
||||||
assertEquals(PBSDefinitions.PBS.getLanguageId(), providers.getFirst().specification().getLanguageId());
|
assertEquals(PBSDefinitions.PBS.getLanguageId(), providers.getFirst().specification().getLanguageId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
void registerShouldResolveAndUnregisterTemporaryProvider() {
|
|
||||||
final var provider = new TemporaryFrontendProvider("registry-temp");
|
|
||||||
FrontendRegistryService.register(provider);
|
|
||||||
try {
|
|
||||||
assertSame(provider, FrontendRegistryService.require("registry-temp"));
|
|
||||||
assertEquals(2, FrontendRegistryService.listProviders().size());
|
|
||||||
} finally {
|
|
||||||
FrontendRegistryService.unregister("registry-temp");
|
|
||||||
}
|
|
||||||
|
|
||||||
assertEquals(1, FrontendRegistryService.listProviders().size());
|
|
||||||
assertEquals(PBSDefinitions.PBS.getLanguageId(),
|
|
||||||
FrontendRegistryService.listProviders().getFirst().specification().getLanguageId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void registerShouldRejectDuplicateLanguageId() {
|
|
||||||
final var provider = new TemporaryFrontendProvider("registry-dup");
|
|
||||||
FrontendRegistryService.register(provider);
|
|
||||||
try {
|
|
||||||
final var thrown = assertThrows(
|
|
||||||
IllegalArgumentException.class,
|
|
||||||
() -> FrontendRegistryService.register(new TemporaryFrontendProvider("registry-dup")));
|
|
||||||
assertTrue(thrown.getMessage().contains("registry-dup"));
|
|
||||||
} finally {
|
|
||||||
FrontendRegistryService.unregister("registry-dup");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void unregisterMustRefuseToRemoveDefaultPbs() {
|
|
||||||
final var thrown = assertThrows(
|
|
||||||
IllegalArgumentException.class,
|
|
||||||
() -> FrontendRegistryService.unregister(PBSDefinitions.PBS.getLanguageId()));
|
|
||||||
|
|
||||||
assertTrue(thrown.getMessage().contains(PBSDefinitions.PBS.getLanguageId()));
|
|
||||||
assertEquals(1, FrontendRegistryService.listProviders().size());
|
|
||||||
assertSame(
|
|
||||||
PBSDefinitions.PBS,
|
|
||||||
FrontendRegistryService.require(PBSDefinitions.PBS.getLanguageId()).specification());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void unregisterUnknownLanguageIdMustBeNoOp() {
|
|
||||||
FrontendRegistryService.unregister(null);
|
|
||||||
FrontendRegistryService.unregister(" ");
|
|
||||||
FrontendRegistryService.unregister("unknown-language");
|
|
||||||
|
|
||||||
assertEquals(1, FrontendRegistryService.listProviders().size());
|
|
||||||
assertEquals(PBSDefinitions.PBS.getLanguageId(),
|
|
||||||
FrontendRegistryService.listProviders().getFirst().specification().getLanguageId());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class TemporaryFrontendProvider implements FrontendProvider {
|
|
||||||
private final FrontendSpec specification;
|
|
||||||
|
|
||||||
private TemporaryFrontendProvider(final String languageId) {
|
|
||||||
this.specification = FrontendSpec.builder()
|
|
||||||
.languageId(languageId)
|
|
||||||
.allowedExtensions(ReadOnlySet.from("tmp"))
|
|
||||||
.sourceRoots(ReadOnlySet.from("src"))
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public FrontendSpec specification() {
|
|
||||||
return specification;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public FrontendPhaseService compiler() {
|
|
||||||
return new FrontendPhaseService() {
|
|
||||||
@Override
|
|
||||||
public IRBackend compile(
|
|
||||||
final FrontendPhaseContext request,
|
|
||||||
final DiagnosticSink diagnostics,
|
|
||||||
final LogAggregator logs,
|
|
||||||
final BuildingIssueSink issues) {
|
|
||||||
return IRBackend.builder().build();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,7 @@ dependencies {
|
|||||||
implementation(project(":prometeu-compiler:prometeu-compiler-core"))
|
implementation(project(":prometeu-compiler:prometeu-compiler-core"))
|
||||||
implementation(project(":prometeu-compiler:prometeu-frontend-api"))
|
implementation(project(":prometeu-compiler:prometeu-frontend-api"))
|
||||||
implementation(project(":prometeu-compiler:prometeu-build-pipeline"))
|
implementation(project(":prometeu-compiler:prometeu-build-pipeline"))
|
||||||
|
implementation(project(":prometeu-compiler:frontends:prometeu-frontend-pbs"))
|
||||||
implementation(project(":prometeu-compiler:prometeu-frontend-registry"))
|
implementation(project(":prometeu-compiler:prometeu-frontend-registry"))
|
||||||
implementation(project(":prometeu-compiler:prometeu-deps"))
|
implementation(project(":prometeu-compiler:prometeu-deps"))
|
||||||
implementation(libs.lsp4j)
|
implementation(libs.lsp4j)
|
||||||
|
|||||||
@ -14,6 +14,7 @@ dependencies {
|
|||||||
implementation(libs.javafx.controls)
|
implementation(libs.javafx.controls)
|
||||||
implementation(libs.javafx.fxml)
|
implementation(libs.javafx.fxml)
|
||||||
implementation(libs.richtextfx)
|
implementation(libs.richtextfx)
|
||||||
|
testImplementation(project(":prometeu-compiler:frontends:prometeu-frontend-pbs"))
|
||||||
testImplementation(project(":prometeu-packer:prometeu-packer-v1"))
|
testImplementation(project(":prometeu-packer:prometeu-packer-v1"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -22,5 +22,3 @@ include("prometeu-compiler:prometeu-frontend-registry")
|
|||||||
include("prometeu-studio")
|
include("prometeu-studio")
|
||||||
|
|
||||||
include("prometeu-app")
|
include("prometeu-app")
|
||||||
|
|
||||||
include("prometeu-architecture-tests")
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user