sdk executable service bodies
This commit is contained in:
parent
4c1a5317dd
commit
ffd5f6c801
@ -1,4 +1,4 @@
|
||||
{"type":"meta","next_id":{"DSC":15,"AGD":16,"DEC":13,"PLN":29,"LSN":30,"CLSN":1}}
|
||||
{"type":"meta","next_id":{"DSC":16,"AGD":17,"DEC":14,"PLN":30,"LSN":30,"CLSN":1}}
|
||||
{"type":"discussion","id":"DSC-0001","status":"done","ticket":"studio-docs-import","title":"Import docs/studio into discussion-framework artifacts","created_at":"2026-03-26","updated_at":"2026-03-26","tags":["studio","migration","discussion-framework","docs-import"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0001","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0001-assets-workspace-execution-wave-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0002","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0002-bank-composition-editor-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0003","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0003-mental-model-asset-mutations-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0004","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0004-mental-model-assets-workspace-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0005","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0005-mental-model-studio-events-and-components-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0006","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0006-mental-model-studio-shell-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0007","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0007-pack-wizard-shell-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0008","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0008-project-scoped-state-and-activity-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0016","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0016-studio-docs-import-pattern.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"}]}
|
||||
{"type":"discussion","id":"DSC-0002","status":"open","ticket":"palette-management-in-studio","title":"Palette Management in Studio","created_at":"2026-03-26","updated_at":"2026-03-26","tags":["studio","legacy-import","palette-management","tile-bank","packer-boundary"],"agendas":[{"id":"AGD-0002","file":"AGD-0002-palette-management-in-studio.md","status":"open","created_at":"2026-03-26","updated_at":"2026-03-26"}],"decisions":[],"plans":[],"lessons":[]}
|
||||
{"type":"discussion","id":"DSC-0003","status":"done","ticket":"packer-docs-import","title":"Import docs/packer into discussion-framework artifacts","created_at":"2026-03-26","updated_at":"2026-03-26","tags":["packer","migration","discussion-framework","docs-import"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0009","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0009-mental-model-packer-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0010","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0010-asset-identity-and-runtime-contract-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0011","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0011-foundations-workspace-runtime-and-build-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0012","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0012-runtime-ownership-and-studio-boundary-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0013","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0013-metadata-convergence-and-runtime-sink-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0014","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0014-pack-wizard-summary-validation-and-pack-execution-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0015","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0015-tile-bank-packing-contract-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0017","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0017-packer-docs-import-pattern.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"}]}
|
||||
@ -13,3 +13,4 @@
|
||||
{"type":"discussion","id":"DSC-0012","status":"done","ticket":"studio-editor-document-vfs-boundary","title":"Definir um boundary de VFS documental para tree/view/open files no Code Editor do Studio","created_at":"2026-03-31","updated_at":"2026-03-31","tags":["studio","editor","workspace","vfs","filesystem","boundary"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0027","file":"discussion/lessons/DSC-0012-studio-editor-document-vfs-boundary/LSN-0027-project-document-vfs-and-session-owned-editor-boundary.md","status":"done","created_at":"2026-03-31","updated_at":"2026-03-31"}]}
|
||||
{"type":"discussion","id":"DSC-0013","status":"done","ticket":"studio-editor-write-wave-supported-non-frontend-files","title":"Definir a wave inicial de edicao no Code Editor apenas para arquivos aceitos e nao relacionados ao FE","created_at":"2026-03-31","updated_at":"2026-04-02","tags":["studio","editor","workspace","write","read-only","vfs","frontend-boundary"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0028","file":"discussion/lessons/DSC-0013-studio-editor-write-wave-supported-non-frontend-files/LSN-0028-controlled-editor-write-wave-and-read-only-frontend-semantic-phase.md","status":"done","created_at":"2026-04-02","updated_at":"2026-04-02"}]}
|
||||
{"type":"discussion","id":"DSC-0014","status":"done","ticket":"studio-frontend-owned-semantic-editor-presentation","title":"Definir ownership do schema visual semantico do editor por frontend","created_at":"2026-04-02","updated_at":"2026-04-02","tags":["studio","editor","frontend","presentation","semantic-highlighting","compiler","pbs"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0029","file":"discussion/lessons/DSC-0014-studio-frontend-owned-semantic-editor-presentation/LSN-0029-frontend-owned-semantic-presentation-descriptor-and-host-consumption.md","status":"done","created_at":"2026-04-02","updated_at":"2026-04-02"}]}
|
||||
{"type":"discussion","id":"DSC-0015","status":"open","ticket":"pbs-service-facade-reserved-metadata","title":"SDK Service Bodies Calling Builtin/Intrinsic Proxies as Ordinary PBS Code","created_at":"2026-04-03","updated_at":"2026-04-03","tags":["compiler","pbs","sdk","stdlib","lowering","service","intrinsic","sdk-interface"],"agendas":[{"id":"AGD-0016","file":"AGD-0016-pbs-service-facade-reserved-metadata.md","status":"accepted","created_at":"2026-04-03","updated_at":"2026-04-03"}],"decisions":[{"id":"DEC-0013","file":"DEC-0013-pbs-sdk-executable-service-bodies.md","status":"accepted","created_at":"2026-04-03","updated_at":"2026-04-03","ref_agenda":"AGD-0016"}],"plans":[{"id":"PLN-0029","file":"PLN-0029-pbs-sdk-executable-service-bodies.md","status":"review","created_at":"2026-04-03","updated_at":"2026-04-03","ref_decisions":["DEC-0013"]}],"lessons":[]}
|
||||
|
||||
@ -0,0 +1,113 @@
|
||||
---
|
||||
id: AGD-0016
|
||||
ticket: pbs-service-facade-reserved-metadata
|
||||
title: SDK Service Bodies Calling Builtin/Intrinsic Proxies as Ordinary PBS Code
|
||||
status: accepted
|
||||
created: 2026-04-03
|
||||
resolved: 2026-04-03
|
||||
decision: DEC-0013
|
||||
tags: [compiler, pbs, sdk, stdlib, lowering, service, intrinsic, sdk-interface]
|
||||
---
|
||||
|
||||
## Pain
|
||||
|
||||
Domain owner: `compiler/pbs`
|
||||
|
||||
The PBS SDK currently supports two stable execution models:
|
||||
|
||||
1. public service wrappers over reserved host declarations such as `@sdk:log`, `@sdk:gfx`, and `@sdk:asset`;
|
||||
2. public builtin-const roots that lower directly to intrinsic owners.
|
||||
|
||||
The input surface now needs a service-oriented version of the intrinsic-backed case:
|
||||
|
||||
- a public `service Input`;
|
||||
- a private builtin type plus builtin const proxy used only inside the SDK;
|
||||
- ordinary PBS service bodies that call the private builtin proxy and return values normally.
|
||||
|
||||
Today this shape parses and passes frontend semantics, but executable lowering does not treat imported SDK service methods as ordinary executable call targets with real bodies. As a result, user code like `Input.touch()` and `Input.pad().a().pressed()` fails with `E_SEM_EXEC_LOWERING_UNRESOLVED_CALLEE` even though the service body itself is valid PBS code.
|
||||
|
||||
## Context
|
||||
|
||||
- `@sdk:input` currently wants to hide the builtin root and expose only the public service.
|
||||
- The lowering path already knows how to:
|
||||
- resolve host-backed service wrappers;
|
||||
- resolve builtin-const-rooted intrinsics.
|
||||
- The intended rule is that SDK service methods should behave as ordinary PBS methods even when their bodies call builtin/intrinsic proxies such as `LowInput`.
|
||||
- Existing tests in the PBS frontend assume `Input` chains resolve to intrinsic callsites and to builtin-owned chained receivers.
|
||||
- The user clarified the desired behavior:
|
||||
- `declare service Input { fn touch() -> InputTouch { let touch = LowInput.touch(); return touch; } }` must compile as normal PBS service code;
|
||||
- the body may include locals and additional processing before returning;
|
||||
- the public callsite does not need to lower directly to the intrinsic as long as the overall executable model works correctly.
|
||||
- Repository workflow requires decision before plan/implementation. This agenda exists to converge on the normative model first.
|
||||
|
||||
## Open Questions
|
||||
|
||||
- [x] What executable artifact model should represent SDK service methods so imported user callsites can lower them as ordinary callable bodies rather than as metadata-only surfaces?
|
||||
Answer: eligible SDK service methods should be represented as ordinary executable callables with lowered bodies available to imported callsites.
|
||||
|
||||
- [x] Should `SDK_INTERFACE` continue forbidding emitted executable bodies globally, or should it gain a selective path for executable service methods that are safe to import and call?
|
||||
Answer: keep the global prohibition by default, but add a narrow selective path for eligible executable SDK service methods.
|
||||
|
||||
- [x] How should chained owner propagation work for values returned from SDK service methods whose bodies call builtin intrinsics, such as `Input.touch()` returning `InputTouch` and `Input.pad()` returning `InputPad`?
|
||||
Answer: owner propagation should follow the value actually returned by the lowered intrinsic call inside the SDK service body, so callers preserve the same chained builtin semantics as direct intrinsic use.
|
||||
|
||||
- [x] What constraints must apply so the compiler can support ordinary SDK service bodies without accidentally turning all interface code into full executable implementation code?
|
||||
Answer: restrict the feature to reserved SDK service methods that stay within a supported executable subset and are explicitly validated as importable/lowerable.
|
||||
|
||||
- [x] Which existing frontend tests must be reoriented from "public callsite resolves directly as intrinsic" to "public service callsite compiles normally and intrinsic resolution succeeds inside the imported method body"?
|
||||
Answer: the `@sdk:input` frontend and lowering tests should be reoriented to validate ordinary service calls, intrinsic lowering inside imported SDK method bodies, and chained owner preservation on returned values.
|
||||
|
||||
- [x] What diagnostics should the compiler emit when an SDK service body calls reserved proxies in ways that cannot be imported or lowered safely?
|
||||
Answer: add dedicated diagnostics for non-importable or non-lowerable executable SDK service bodies instead of collapsing to generic unresolved-callee failures.
|
||||
|
||||
## Options
|
||||
|
||||
### Option A - Treat SDK Service Bodies as Ordinary Executable Callables
|
||||
- **Approach:** Preserve executable bodies for eligible SDK service methods and import them as ordinary callable targets. Lowering of user code emits `CALL_FUNC` to the service method, and the service body itself lowers calls like `LowInput.touch()` to intrinsics.
|
||||
- **Pro:** Matches the intended product model exactly. Keeps service semantics ordinary and avoids facade-specific lowering rules.
|
||||
- **Con:** Requires widening the current `SDK_INTERFACE` lowering model, which today suppresses emitted function bodies.
|
||||
- **Maintainability:** Strong if the eligibility rules stay explicit and narrow.
|
||||
|
||||
### Option B - Explicit Reserved Facade Metadata on Service Methods
|
||||
- **Approach:** Add explicit reserved metadata on service methods declaring which intrinsic owner and method they represent. Lowering may continue to skip executable imported service bodies and instead lower the public callsite through the reserved metadata bridge.
|
||||
- **Pro:** Smaller execution-model change than importing executable service bodies.
|
||||
- **Con:** It does not deliver the user-requested semantics of "ordinary PBS service code with arbitrary local processing". It also creates a special case distinct from normal service behavior.
|
||||
- **Maintainability:** Medium. More explicit than inference, but still introduces a second-class meaning for service methods.
|
||||
|
||||
### Option C - Keep Builtin Root Public for Intrinsic-Backed SDK Modules
|
||||
- **Approach:** Continue exposing builtin const roots publicly and avoid service wrappers for intrinsic-backed modules such as `@sdk:input`.
|
||||
- **Pro:** Reuses the current lowering path with minimal compiler work.
|
||||
- **Con:** Conflicts directly with the intended SDK API shape and the user requirement that `Input` remain a normal public service.
|
||||
- **Maintainability:** Medium for the compiler, weak for the SDK/API design because it leaks implementation-facing reserved roots into public user code.
|
||||
|
||||
## Discussion
|
||||
|
||||
The user clarified that the target model is not a special "facade intrinsic" abstraction. The target model is ordinary service execution:
|
||||
|
||||
- SDK service methods should behave like normal PBS service methods;
|
||||
- they may call private reserved proxies such as `LowInput`;
|
||||
- they may allocate locals, perform intermediate work, and then return;
|
||||
- callers should not need direct access to the reserved proxy.
|
||||
|
||||
The core mismatch is therefore different from the original framing. `Log`, `Gfx`, and `Assets` work because the compiler already supports the relevant host-backed wrappers under the current SDK model. `Input` fails because intrinsic-backed SDK service bodies are not currently imported and lowered as ordinary executable code paths.
|
||||
|
||||
The compiler therefore likely needs first-class support for executable SDK service bodies, or an explicitly accepted alternative that is intentionally less general than normal service semantics.
|
||||
|
||||
## Resolution
|
||||
|
||||
Recommended direction: pursue **Option A - Treat SDK Service Bodies as Ordinary Executable Callables**.
|
||||
|
||||
Why:
|
||||
|
||||
- it matches the clarified requirement exactly: the public `service Input` should work as ordinary PBS code;
|
||||
- it allows locals and additional processing inside the method body without requiring special facade inference;
|
||||
- it keeps the private builtin proxy as an implementation detail rather than a user-facing surface;
|
||||
- it avoids introducing a second semantic class of service methods that only pretend to be ordinary services.
|
||||
|
||||
Suggested next step:
|
||||
|
||||
1. write a decision that defines the SDK executable model for service methods that call reserved proxies;
|
||||
2. specify how imported SDK service bodies are represented, lowered, and validated;
|
||||
3. derive an implementation plan from that accepted decision.
|
||||
|
||||
The discussion is now converged enough to move to the decision stage.
|
||||
@ -0,0 +1,159 @@
|
||||
---
|
||||
id: DEC-0013
|
||||
ticket: pbs-service-facade-reserved-metadata
|
||||
title: Executable SDK Service Bodies for Builtin/Intrinsic-Backed Public Services
|
||||
status: accepted
|
||||
created: 2026-04-03
|
||||
accepted: 2026-04-03
|
||||
agenda: AGD-0016
|
||||
plans: [PLN-0029]
|
||||
tags: [compiler, pbs, sdk, stdlib, lowering, service, intrinsic, sdk-interface]
|
||||
---
|
||||
|
||||
## Decision
|
||||
|
||||
Domain owner: `compiler/pbs`
|
||||
|
||||
The PBS compiler SHALL support a restricted executable-service model inside `SDK_INTERFACE` sources.
|
||||
|
||||
Under this model:
|
||||
|
||||
1. public SDK `service` methods MAY contain ordinary PBS executable bodies;
|
||||
2. those bodies MAY call reserved hosts, reserved builtin const proxies, and reserved intrinsic-backed values;
|
||||
3. imported user callsites to eligible SDK service methods SHALL lower as ordinary callable invocations of the SDK service method body;
|
||||
4. intrinsic lowering SHALL occur inside the lowered SDK service body when the body calls the private reserved proxy;
|
||||
5. public user code MUST NOT be required to import or reference the private reserved proxy directly.
|
||||
|
||||
This decision explicitly rejects the requirement that intrinsic-backed public SDK services MUST lower directly from the user callsite to `CALL_INTRINSIC`.
|
||||
|
||||
For eligible SDK service methods, the normative lowering model is:
|
||||
|
||||
- public user callsite lowers as callable/service method invocation;
|
||||
- imported SDK service body lowers as executable PBS code;
|
||||
- reserved proxy calls inside that body lower through the existing intrinsic or host machinery;
|
||||
- returned values preserve the owner and chaining semantics established by the lowered reserved operation.
|
||||
|
||||
`@sdk:input` SHALL be supported by this model. A service body such as:
|
||||
|
||||
```pbs
|
||||
declare service Input {
|
||||
fn touch() -> InputTouch {
|
||||
let touch = LowInput.touch();
|
||||
return touch;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
MUST be valid as ordinary SDK service code, provided it remains within the supported restricted subset defined below.
|
||||
|
||||
## Rationale
|
||||
|
||||
This decision matches the intended SDK API shape:
|
||||
|
||||
- public SDK surfaces such as `Input` should be expressed as services when that is the product-facing abstraction;
|
||||
- private reserved builtins and builtin const proxies should remain implementation details;
|
||||
- SDK authors must be allowed to write normal service bodies with locals and intermediate processing rather than being forced into synthetic facade metadata or direct public builtin roots.
|
||||
|
||||
The alternative of explicit facade metadata on public service methods was rejected because it creates a second semantic class of services that only imitate ordinary PBS code. The alternative of keeping intrinsic roots public was rejected because it leaks reserved implementation surfaces into the user API.
|
||||
|
||||
## Technical Specification
|
||||
|
||||
### 1. Eligible Surface
|
||||
|
||||
The compiler SHALL define an explicit category of eligible executable SDK service methods.
|
||||
|
||||
An eligible executable SDK service method:
|
||||
|
||||
1. MUST be declared in a `SourceKind.SDK_INTERFACE` module;
|
||||
2. MUST belong to a `service` declaration;
|
||||
3. MUST remain within the restricted executable subset defined by compiler validation;
|
||||
4. MUST be importable as a callable body by user modules.
|
||||
|
||||
Non-eligible declarations in `SDK_INTERFACE` MUST continue to follow the existing non-executable interface rules.
|
||||
|
||||
### 2. SDK Interface Execution Boundary
|
||||
|
||||
`SDK_INTERFACE` SHALL remain non-executable by default.
|
||||
|
||||
The compiler SHALL introduce a narrow exception for eligible SDK service methods only. This exception MUST NOT implicitly generalize to arbitrary interface-level functions, globals, or unrestricted executable declarations.
|
||||
|
||||
### 3. Import Model
|
||||
|
||||
When a user module imports a public SDK service:
|
||||
|
||||
1. the imported semantic surface MUST continue to expose the service method signatures;
|
||||
2. the lowering pipeline MUST also have access to the executable body of each eligible imported SDK service method;
|
||||
3. a user callsite such as `Input.touch()` MUST be lowerable as an ordinary callable invocation of the imported SDK service method.
|
||||
|
||||
The compiler MUST NOT require special public facade metadata to connect the user callsite to the reserved intrinsic owner when the service body already expresses the call explicitly.
|
||||
|
||||
### 4. Lowering Model
|
||||
|
||||
For an eligible imported SDK service method:
|
||||
|
||||
1. the public callsite SHALL lower as a callable invocation;
|
||||
2. the imported SDK service body SHALL be lowered with the same executable-body discipline applied to ordinary PBS executable code, subject to the restricted subset;
|
||||
3. calls inside that body to reserved hosts SHALL continue to use host lowering;
|
||||
4. calls inside that body to reserved builtin const proxies SHALL continue to use intrinsic lowering;
|
||||
5. any returned reserved value SHALL preserve the return owner and chaining semantics inferred from the lowered reserved call.
|
||||
|
||||
As a result:
|
||||
|
||||
- `Input.touch()` MAY lower to a callable invocation of the imported SDK method;
|
||||
- `LowInput.touch()` inside the SDK body SHALL lower to the intrinsic owner `input.touch`;
|
||||
- chained user code such as `Input.touch().x()` and `Input.pad().a().pressed()` MUST remain valid when the returned owner chain is supported by the reserved metadata.
|
||||
|
||||
### 5. Restricted Executable Subset
|
||||
|
||||
The compiler SHALL validate eligible executable SDK service methods against an explicit restricted subset.
|
||||
|
||||
At minimum, the first supported subset MUST permit:
|
||||
|
||||
- local bindings;
|
||||
- ordinary return statements;
|
||||
- calls to reserved hosts;
|
||||
- calls to reserved builtin const proxies and their intrinsic-return values;
|
||||
- straightforward expression composition needed for wrapper-style service methods.
|
||||
|
||||
The first supported subset MUST NOT silently permit unsupported executable constructs. If a construct is outside the supported subset, the compiler MUST emit a dedicated diagnostic.
|
||||
|
||||
Whether control flow beyond straightforward wrapper composition is included in the first wave SHALL be decided in planning and implementation, but the compiler MUST validate the boundary explicitly rather than relying on accidental behavior.
|
||||
|
||||
### 6. Diagnostics
|
||||
|
||||
The compiler SHALL add dedicated diagnostics for executable SDK service bodies that cannot be imported or lowered safely.
|
||||
|
||||
These diagnostics MUST distinguish this failure mode from generic unresolved callee failures.
|
||||
|
||||
At minimum, diagnostics SHALL cover:
|
||||
|
||||
- SDK service bodies that use unsupported executable constructs;
|
||||
- imported SDK service methods that are not eligible for executable lowering;
|
||||
- inconsistencies between an imported SDK service signature and the lowered executable body shape;
|
||||
- reserved proxy use that cannot preserve required return-owner or chaining behavior.
|
||||
|
||||
### 7. Tests and Conformance
|
||||
|
||||
The compiler test suite SHALL be updated to reflect the new normative model.
|
||||
|
||||
Tests MUST cover:
|
||||
|
||||
1. public SDK service callsites lowering successfully as callable invocations;
|
||||
2. intrinsic lowering occurring inside the imported SDK service body;
|
||||
3. returned reserved owners preserving chained method access for values such as `InputTouch` and `InputPad`;
|
||||
4. use of locals and intermediate processing inside SDK service bodies;
|
||||
5. dedicated diagnostics for unsupported executable SDK service bodies.
|
||||
|
||||
Existing tests that assume the public `Input` callsite itself MUST resolve directly to an intrinsic SHALL be revised to match this decision.
|
||||
|
||||
## Constraints
|
||||
|
||||
- This decision applies to `compiler/pbs` and to SDK surfaces loaded through `SDK_INTERFACE`.
|
||||
- This decision does not authorize arbitrary executable code throughout interface modules.
|
||||
- This decision does not require public exposure of private reserved builtin roots.
|
||||
- This decision does not replace the existing host-backed SDK service model; it extends the compiler so intrinsic-backed SDK services can use ordinary service bodies.
|
||||
- Any future extension of the restricted executable subset MUST be treated as a follow-up decision or explicit revision if it changes the initial boundary materially.
|
||||
|
||||
## Revision Log
|
||||
|
||||
- 2026-04-03: Initial draft from AGD-0016.
|
||||
@ -0,0 +1,181 @@
|
||||
---
|
||||
id: PLN-0029
|
||||
ticket: pbs-service-facade-reserved-metadata
|
||||
title: Implement Restricted Executable SDK Service Bodies for Intrinsic-Backed Public Services
|
||||
status: review
|
||||
created: 2026-04-03
|
||||
completed:
|
||||
tags: [compiler, pbs, sdk, stdlib, lowering, service, intrinsic, sdk-interface]
|
||||
---
|
||||
|
||||
## Objective
|
||||
|
||||
Implement the `DEC-0013` model for restricted executable SDK service bodies so public SDK services such as `@sdk:input` compile as ordinary PBS service code while preserving host and intrinsic lowering inside imported SDK service bodies.
|
||||
|
||||
## Background
|
||||
|
||||
`DEC-0013` accepts the model where:
|
||||
|
||||
- `SDK_INTERFACE` remains non-executable by default;
|
||||
- eligible SDK `service` methods gain a narrow executable path;
|
||||
- user callsites lower as ordinary callable invocations of imported SDK service methods;
|
||||
- host and intrinsic lowering continue to happen inside the imported SDK service body;
|
||||
- returned reserved values preserve owner and chaining behavior;
|
||||
- dedicated diagnostics replace generic unresolved-callee failures for unsupported cases.
|
||||
|
||||
The current compiler exposes imported SDK service signatures but does not provide an executable-body path for intrinsic-backed service wrappers such as `Input.touch()` and `Input.pad()`. The plan below closes that gap without generalizing arbitrary executable code across all interface declarations.
|
||||
|
||||
## Scope
|
||||
|
||||
### Included
|
||||
- Defining and validating eligibility rules for executable SDK service methods.
|
||||
- Representing eligible SDK service method bodies so imported user callsites can lower them as ordinary callable invocations.
|
||||
- Lowering imported SDK service bodies under a restricted executable subset.
|
||||
- Preserving owner propagation and chained reserved behavior for returned intrinsic-backed values.
|
||||
- Adding dedicated diagnostics for unsupported executable SDK service bodies.
|
||||
- Updating frontend and integration tests to reflect the accepted model.
|
||||
|
||||
### Excluded
|
||||
- General executable support for arbitrary `SDK_INTERFACE` functions, globals, or unrestricted declarations.
|
||||
- Public exposure of private reserved builtin roots.
|
||||
- Expansion of the restricted executable subset beyond the first explicitly supported wave unless needed to satisfy `DEC-0013`.
|
||||
- Editorial changes to unrelated SDK modules.
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1 - Define the Executable SDK Service Eligibility Boundary
|
||||
|
||||
**What:** Introduce the compiler-side concept of an eligible executable SDK service method and enforce the first restricted subset accepted by `DEC-0013`.
|
||||
|
||||
**How:** Add validation logic that runs on `SourceKind.SDK_INTERFACE` service methods and classifies each method as either executable/importable or rejected with a dedicated diagnostic. The first supported subset must explicitly allow local bindings, ordinary returns, calls to reserved hosts, calls to reserved builtin const proxies, intrinsic-return chaining, and straightforward wrapper-style expression composition. Any construct outside that subset must fail deterministically with a dedicated diagnostic instead of reaching generic lowering failure.
|
||||
|
||||
**File(s):**
|
||||
- `prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/semantics/PbsDeclarationSemanticsValidator.java`
|
||||
- `prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/semantics/...` as needed for executable-subset validation
|
||||
- `prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/PbsSemanticsErrors.java`
|
||||
|
||||
### Step 2 - Expose Imported SDK Service Bodies to the Lowering Pipeline
|
||||
|
||||
**What:** Extend imported SDK context assembly so eligible SDK service methods are available not only as callable signatures but also as executable bodies that user modules can target.
|
||||
|
||||
**How:** Enrich the imported semantic/lowering context with per-method executable metadata for eligible SDK service methods, including module identity, owning service, signature shape, AST/body reference, and any lowering metadata required to compile the imported method body exactly once in a controlled way. Preserve the existing lightweight path for non-executable interface declarations.
|
||||
|
||||
**File(s):**
|
||||
- `prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/services/PbsImportedSemanticContextService.java`
|
||||
- `prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/services/PbsImportedSemanticContext.java`
|
||||
- `prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/PbsFrontendCompiler.java`
|
||||
- `prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/messages/FESurfaceContext.java`
|
||||
|
||||
### Step 3 - Lower Public SDK Service Calls as Callable Invocations of Imported Bodies
|
||||
|
||||
**What:** Make user callsites such as `Input.touch()` and `Input.pad()` resolve as callable invocations of imported executable SDK service methods.
|
||||
|
||||
**How:** Update callable resolution and lowering metadata so eligible imported SDK service methods participate as ordinary callable targets with executable bodies rather than metadata-only surfaces. Ensure public service callsites resolve to `CALL_FUNC`-style lowering when appropriate and do not require public facade metadata or direct builtin-root identity at the callsite itself.
|
||||
|
||||
**File(s):**
|
||||
- `prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/lowering/PbsExecutableCallsiteEmitter.java`
|
||||
- `prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/lowering/PbsExecutableLoweringService.java`
|
||||
- `prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/lowering/PbsExecutableLoweringContext.java`
|
||||
- `prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/lowering/PbsExecutableLoweringModels.java`
|
||||
|
||||
### Step 4 - Lower Imported SDK Service Method Bodies Under the Restricted Subset
|
||||
|
||||
**What:** Add the executable-body lowering path for eligible imported SDK service methods so reserved host and intrinsic calls continue to lower inside the SDK method body itself.
|
||||
|
||||
**How:** Reuse as much of the existing executable lowering pipeline as possible, but constrain it to imported eligible SDK service methods. Ensure the lowering path supports locals, returns, reserved host calls, reserved builtin const proxy calls, and direct wrapper-style logic. Prevent accidental lowering of unsupported or non-eligible interface code.
|
||||
|
||||
**File(s):**
|
||||
- `prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/lowering/PbsExecutableBodyLowerer.java`
|
||||
- `prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/lowering/PbsExecutableMetadataIndexFactory.java`
|
||||
- `prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/lowering/PbsExecutableCallsiteEmitter.java`
|
||||
|
||||
### Step 5 - Preserve Return Owner and Chaining Semantics Across SDK Service Returns
|
||||
|
||||
**What:** Ensure values returned by imported SDK service methods keep the same reserved owner identity and chaining behavior as the intrinsic/host-backed values produced inside the method body.
|
||||
|
||||
**How:** Propagate owner metadata from the lowered reserved call through the return path of the imported SDK service method so downstream user expressions such as `Input.touch().x()` and `Input.pad().a().pressed()` retain resolvable chained semantics. Add targeted validation when the compiler cannot preserve this owner chain safely.
|
||||
|
||||
**File(s):**
|
||||
- `prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/lowering/PbsExecutableMetadataIndexFactory.java`
|
||||
- `prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/lowering/PbsExecutableCallsiteEmitter.java`
|
||||
- `prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/lowering/PbsExecutableLoweringContext.java`
|
||||
|
||||
### Step 6 - Introduce Dedicated Diagnostics for Non-Lowerable SDK Service Bodies
|
||||
|
||||
**What:** Replace generic unresolved-callee failures with dedicated diagnostics for unsupported executable SDK service bodies.
|
||||
|
||||
**How:** Add explicit error codes and reporting paths for:
|
||||
- non-eligible executable SDK service methods;
|
||||
- unsupported constructs inside executable SDK service bodies;
|
||||
- signature/body inconsistencies for imported executable SDK service methods;
|
||||
- unpreservable reserved owner/chaining cases.
|
||||
|
||||
Wire these diagnostics so failures are emitted at validation/lowering time with stable code identity and source spans.
|
||||
|
||||
**File(s):**
|
||||
- `prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/PbsSemanticsErrors.java`
|
||||
- `prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/lowering/...`
|
||||
- `prometeu-compiler/frontends/prometeu-frontend-pbs/src/test/java/...` diagnostic contract tests
|
||||
|
||||
### Step 7 - Update and Expand Tests to Match DEC-0013
|
||||
|
||||
**What:** Align the PBS frontend and pipeline test suite with the accepted executable SDK service body model.
|
||||
|
||||
**How:** Update existing `@sdk:input` tests that currently assume public callsites lower directly to intrinsics. Add coverage for:
|
||||
- public `Input.touch()` and `Input.pad()` callsites lowering successfully through imported SDK service bodies;
|
||||
- intrinsic lowering occurring inside those imported bodies;
|
||||
- locals and intermediate processing inside SDK service bodies;
|
||||
- returned owner and chained calls such as `touch.x()` and `Input.pad().a().pressed()`;
|
||||
- dedicated diagnostics when an executable SDK service body violates the restricted subset.
|
||||
|
||||
**File(s):**
|
||||
- `prometeu-compiler/frontends/prometeu-frontend-pbs/src/test/java/p/studio/compiler/services/PBSFrontendPhaseServiceTest.java`
|
||||
- `prometeu-compiler/frontends/prometeu-frontend-pbs/src/test/java/p/studio/compiler/pbs/PbsFrontendCompilerTest.java`
|
||||
- `prometeu-compiler/frontends/prometeu-frontend-pbs/src/test/java/p/studio/compiler/pbs/PbsGateUSdkInterfaceConformanceTest.java`
|
||||
- `prometeu-compiler/prometeu-build-pipeline/src/test/java/p/studio/compiler/integration/MainProjectPipelineIntegrationTest.java`
|
||||
- related diagnostic/lowering tests as needed
|
||||
|
||||
## Test Requirements
|
||||
|
||||
### Unit Tests
|
||||
|
||||
- Validation tests for executable SDK service method eligibility and restricted-subset rejection.
|
||||
- Lowering tests for imported SDK service callsites resolving as callable invocations.
|
||||
- Lowering tests for intrinsic and host operations inside imported SDK service bodies.
|
||||
- Owner-propagation tests for returned reserved values and chained member calls.
|
||||
- Diagnostic identity tests for each new SDK executable-service failure mode.
|
||||
|
||||
### Integration Tests
|
||||
|
||||
- Pipeline test proving `test-projects/main` compiles successfully when `@sdk:input` is expressed as a public service over a private builtin proxy.
|
||||
- Integration coverage for mixed SDK modules so existing host-backed wrappers (`Log`, `Gfx`, `Assets`) continue to work unchanged alongside the new intrinsic-backed service model.
|
||||
|
||||
### Manual Verification
|
||||
|
||||
- Run the compile pipeline against the main test project with the service-based `@sdk:input` shape.
|
||||
- Verify the resulting IR contains callable lowering for the public SDK service entrypoint and intrinsic lowering inside the imported SDK service body.
|
||||
- Confirm unsupported SDK executable constructs emit the new dedicated diagnostics rather than `E_SEM_EXEC_LOWERING_UNRESOLVED_CALLEE`.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] Eligible SDK service methods in `SDK_INTERFACE` can be imported with executable bodies while the rest of the interface surface remains non-executable by default.
|
||||
- [ ] Public callsites such as `Input.touch()` and `Input.pad()` lower as callable invocations of imported SDK service methods.
|
||||
- [ ] Reserved host and intrinsic calls inside imported SDK service bodies lower correctly through the existing reserved machinery.
|
||||
- [ ] Returned reserved values preserve owner/chaining semantics for expressions such as `Input.touch().x()` and `Input.pad().a().pressed()`.
|
||||
- [ ] Unsupported executable SDK service bodies fail with dedicated diagnostics instead of generic unresolved-callee errors.
|
||||
- [ ] Existing host-backed SDK services continue to compile without regression.
|
||||
- [ ] Frontend and integration tests reflect and enforce the accepted model from `DEC-0013`.
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Accepted decision: `DEC-0013`.
|
||||
- Existing reserved metadata and intrinsic lowering infrastructure in the PBS frontend.
|
||||
- Existing imported semantic-context assembly for SDK modules.
|
||||
- Existing host-backed SDK service behavior must remain as the regression baseline.
|
||||
|
||||
## Risks
|
||||
|
||||
- The executable-service exception for `SDK_INTERFACE` could accidentally broaden into support for arbitrary interface code if the eligibility boundary is not enforced centrally.
|
||||
- Owner propagation across imported SDK service returns may require careful threading of metadata through call/return paths and could regress chained intrinsic resolution if partially implemented.
|
||||
- Reusing ordinary executable lowering for imported SDK bodies may expose assumptions that currently only hold for project-local executable functions.
|
||||
- Test expectations that currently assert direct intrinsic callsites may need careful revision to avoid preserving obsolete invariants.
|
||||
@ -1,5 +1,5 @@
|
||||
[BuiltinType(name = "input", version = 1)]
|
||||
declare builtin type Input() {
|
||||
declare builtin type InputType() {
|
||||
[IntrinsicCall(name = "pad", version = 1)]
|
||||
fn pad() -> InputPad;
|
||||
|
||||
@ -74,4 +74,19 @@ declare builtin type InputButton() {
|
||||
}
|
||||
|
||||
[BuiltinConst(target = "input", name = "global", version = 1)]
|
||||
declare const Input: Input;
|
||||
declare const LowInput: InputType;
|
||||
|
||||
declare service Input
|
||||
{
|
||||
fn pad() -> InputPad
|
||||
{
|
||||
let pad = LowInput.pad();
|
||||
return pad;
|
||||
}
|
||||
|
||||
fn touch() -> InputTouch
|
||||
{
|
||||
let touch = LowInput.touch();
|
||||
return touch;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
pub struct Input;
|
||||
pub struct InputPad;
|
||||
pub struct InputTouch;
|
||||
pub struct InputButton;
|
||||
pub const Input;
|
||||
pub service Input;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
package p.studio.utilities;
|
||||
|
||||
public class PConstants {
|
||||
public static final String PROJECT = "fragments";
|
||||
public static final String PROJECT = "main";
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user