--- id: LSN-0030 ticket: pbs-service-facade-reserved-metadata title: SDK Service Bodies Over Private Reserved Proxies created: 2026-04-03 tags: [compiler, pbs, sdk, stdlib, lowering, service, intrinsic, sdk-interface] --- ## Context PBS originally supported two clear execution shapes for SDK surfaces: - public service wrappers over reserved hosts such as `Log`, `Gfx`, and `Assets`; - public builtin roots that lower directly to intrinsics. The `@sdk:input` surface exposed a third requirement: keep the public API as a normal `service`, keep the builtin proxy private, and still allow user code like `Input.touch().x()` and `Input.pad().a().pressed()` to compile and lower correctly. The core pitfall was assuming the public callsite itself still had to lower directly to `CALL_INTRINSIC`. That assumption forced the public API shape back toward builtin roots and broke the intended service abstraction. ## Key Decisions ### Executable SDK Service Bodies for Builtin/Intrinsic-Backed Public Services **What:** The accepted model keeps `SDK_INTERFACE` non-executable by default, but allows a restricted executable subset for SDK service methods. Public callsites such as `Input.touch()` lower as ordinary callable invocations of imported SDK service methods, while intrinsic lowering happens inside those imported method bodies when they call private reserved proxies such as `LowInput`. **Why:** This preserves the intended product-facing API shape. SDK authors can write ordinary service bodies with locals and intermediate processing instead of exposing private builtin roots or inventing a second-class metadata-only facade system. **Trade-offs:** The compiler must preserve owner/chaining semantics across callable returns, not only across direct intrinsic callsites. It also needs an explicit subset boundary and dedicated diagnostics so the executable exception for `SDK_INTERFACE` does not silently widen into arbitrary interface execution. ## Patterns and Algorithms - Model the public SDK API as a normal service surface and keep the private reserved proxy internal. - Let the public user callsite lower as `CALL_FUNC` when the service method is the correct public abstraction. - Preserve reserved owner metadata on callable returns so chained expressions continue to resolve after the service call boundary. - Validate executable SDK service bodies against an explicit initial subset instead of inferring support from whatever lowering happens to tolerate. - Emit dedicated diagnostics for unsupported SDK executable constructs rather than collapsing to a generic unresolved-callee error. ## Pitfalls - Do not assume every intrinsic-backed public SDK surface should lower directly from the public callsite to `CALL_INTRINSIC`. - Do not leak private builtin roots into the public API merely because the existing lowering path already understands them. - Do not add a broad executable mode to all `SDK_INTERFACE` declarations when only a narrow service-method subset is intended. - Do not rely on old tests that assert direct intrinsic callsites once the accepted model changes to callable public entrypoints plus intrinsic lowering inside imported SDK bodies. ## Takeaways - Preserve the public API shape first, then adapt lowering to it when the abstraction is intentional. - Owner propagation across callable returns is the critical mechanism that makes service-over-intrinsic wrappers behave like ordinary PBS code. - A restricted executable subset plus dedicated diagnostics is safer than implicit support for arbitrary interface code.