# Phase 03 – Rigid Frontend API & PBS Leak Containment (Junie PR Templates) > Goal: **finish Phase 03 with JVM-like discipline** by making the **Backend (BE) the source of truth** and forcing the PBS Frontend (FE) to implement a **strict, minimal, canonical** contract (`frontend-api`). > > Strategy: **surgical PRs** that (1) stop PBS types from leaking, (2) replace stringy protocols with canonical models, and (3) make imports/exports/overloads deterministic across deps. --- ## PR-03.03 — Canonical import syntax → `ImportRef` (no dual styles) ### Title Define single canonical import model and parse PBS imports into `ImportRef` ### Briefing / Context We currently support multiple synthetic import path styles (`"alias/module"` and `"@alias:module"`). This amplifies ambiguity and is a root cause of mismatch in imported service method overloads. We want **one** canonical representation: * PBS syntax: `import { Test } from "@sdk:input/testing"` * Canonical model: `ImportRef { project: "sdk", module: "input/testing", item: "Test" }` ### Target * PBS FE produces a list of canonical `ImportRef`. * BE consumes only `ImportRef`. * Remove support for dual synthetic path style in the BE pipeline. ### Scope * In PBS FE: * Parse `@:` into `ImportRef`. * Validate module path normalization. * Validate that `item` is a single symbol name (service/struct/host/contract/etc). * In BE: * Replace “synthetic path generation” with canonical module lookup using `(alias, module_path)`. ### Out of scope * Export naming canonicalization (PR-03.04/03.05). ### Checklist * [ ] Implement import parser → `ImportRef`. * [ ] Remove `alias/module` synthetic path support. * [ ] Update resolver/module-provider lookup to accept `(alias, module_path)`. * [ ] Add diagnostics for invalid import string. ### Tests * Unit tests in PBS FE for: * valid: `"@sdk:input/testing"` * invalid forms * normalization edge cases (leading `/`, `./`, `\\` on Windows paths) * Integration test (golden-style) compiling a small project importing a service. ### Risk Medium. Changes import resolution plumbing. --- ## PR-03.04 — Canonical function identity: `CanonicalFnKey` (JVM-like) ### Title Introduce canonical function identity for exports/import calls (no string prefix matching) ### Briefing / Context Phase 03 currently tries to match overloads using `name#sigN` strings + prefix logic + origin checks. This breaks easily and is exactly what produced `E_OVERLOAD_NOT_FOUND` for `Log.debug`. We need a **canonical function key** that is not “string protocol”: * `CanonicalFnKey { owner: Option, name: ItemName, sig: SigId }` * Free fn: `owner=None, name=foo, sig=...` * Service method: `owner=Some(Log), name=debug, sig=...` ### Target * BE uses `CanonicalFnKey` for export surface and import relocation. * FE supplies `owner/name` and produces/requests signatures deterministically. ### Scope * Add `CanonicalFnKey` to `frontend-api`. * Update VM import call instruction payload to carry canonical pieces: * `ImportCall { dep_alias, module_path, fn_key: CanonicalFnKey, arg_count }` * (or equivalent) * Eliminate string matching / prefix matching for overload selection. ### Checklist * [ ] Define `CanonicalFnKey` and helpers. * [ ] Update IR / bytecode instruction structures if needed. * [ ] Update lowering call sites. * [ ] Ensure debug info keeps readable names (owner.name). ### Tests * Unit: canonical formatting for debug name `Log.debug`. * Integration: two overloads of `Log.debug` across deps resolved by exact signature. ### Risk High-ish. Touches instruction encoding and matching logic. --- ## PR-03.05 — Canonical export surface: `ExportItem` (no `svc:` / no `name#sig` strings) ### Title Replace stringy export naming with canonical `ExportItem` model ### Briefing / Context Exports are currently keyed by `(module_path, symbol_name string, kind)` where symbol_name embeds `#sig` and/or owner names. This is fragile and couples FE naming to BE behavior. ### Target * BE export map keys are canonical: * `ExportItem::Type { name }` * `ExportItem::Service { name }` * `ExportItem::Function { fn_key: CanonicalFnKey }` * Export surface remains stable even if we later change display formatting. ### Scope * Update compiled module export structures. * Update dependency symbol synthesis to use canonical export items. * Update linker relocation labels to reference canonical export items. ### Checklist * [ ] Introduce `ExportItem` and migrate ExportKey. * [ ] Update dependency export synthesis. * [ ] Update linker/import label format (if used) to canonical encoding. * [ ] Ensure backward compatibility is explicitly NOT required for Phase 03. ### Tests * Unit: exporting a service method yields `ExportItem::Function { owner=Log, name=debug, sig=... }`. * Integration: build root + dep, link, run golden. ### Risk High. Touches serialization and linking labels. --- ## PR-03.06 — Deterministic overload resolution across deps (arity is not enough) ### Title Implement deterministic overload selection using canonical signature matching ### Briefing / Context We currently try to disambiguate overloads by arity as a fallback. That’s not sufficient (same arity, different types). For Phase 03 “professional grade”, overload resolution must be deterministic and match by full signature. ### Target * Imported method call selects overload by: 1. resolve callee symbol → candidate set 2. typecheck args → determine expected param types 3. choose exact match 4. otherwise `E_OVERLOAD_NOT_FOUND` or `E_OVERLOAD_AMBIGUOUS` deterministically ### Scope * PBS FE typechecker must provide enough info to compute signature selection. * Resolver must expose all overload candidates for an imported `ImportRef` item. * Lowering uses canonical fn key and selected `SigId`. ### Checklist * [ ] Ensure imported service methods are actually present in imported symbol arena. * [ ] Ensure candidates include `(owner, name, sig)` not just `name`. * [ ] Implement exact-match algorithm. * [ ] Implement deterministic ambiguity ordering for diagnostics. ### Tests * Add golden regression reproducing `Log.debug` failure: * dep exports `service Log { debug(string) }` * root imports `Log` and calls `Log.debug("x")` * Add tests for: * ambiguous same signature * not found ### Risk Medium/High. Needs clean integration across resolver/typechecker/lowering. --- ## PR-03.07 — Phase 03 cleanup: remove legacy compatibility branches and document boundary ### Title Remove legacy string protocol branches and document FE/BE boundary rules ### Briefing / Context After canonical models are in place, we must delete compatibility code paths (`alias/module`, `svc:` prefixes, prefix matching, etc.) to prevent regressions. ### Target * No legacy synthetic module path support. * No string prefix matching for overloads. * Documentation: “BE owns the contract; FE implements it.” ### Scope * Delete dead code. * Add `docs/phase-03-frontend-api.md` (or in-crate docs) summarizing invariants. * Add CI/lints to prevent BE from importing PBS modules. ### Checklist * [ ] Remove legacy branches. * [ ] Add boundary docs. * [ ] Add lint/CI guard. ### Tests * Full workspace tests. * Golden tests. ### Risk Low/Medium. Mostly deletion + docs, but could expose hidden dependencies. --- # Notes / Operating Rules (for Junie) 1. **BE is the source of truth**: `frontend-api` defines canonical models; FE conforms. 2. **No string protocols** across layers. Strings may exist only as *display/debug*. 3. **No FE implementation imports from other FE implementations**. 4. **No BE imports PBS modules** (hard boundary). 5. **Overload resolution is signature-based** (arity alone is not valid).