---
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.
