Repository navigation
Description
Problem
docs/emitters/refine/naming.md promises: "Collisions are resolved deterministically in Ctx.Syms, which is keyed by IR ID: adding one endpoint never renames an existing method." The mechanism it names does not deliver that promise. Keying by ID and being deterministic are both necessary but neither is sufficient: a function of the current document alone cannot tell which of two colliding operations shipped first.
Cloudflare's Forge is a working counterexample: packages/forge/shared/sdk-method-names.ts at cloudflare/forge@00b8ede. Its renamer is deterministic, order-independent (it renames every member of a collision from that member's own identity) and keyed by operationId, so it has every property docs/emitters/refine/naming.md names. Run it on two revisions of one group:
| Revision | Operations in group zones with method name get |
Resulting names |
|---|---|---|
| v1 | zones-get-zone |
get |
| v2 | zones-get-zone, zones-get-zone-settings |
zonesGetZone, zonesGetZoneSettings |
Adding one endpoint renamed the method v1 shipped, which is a breaking SDK change. Reversing the input order gives the same v2 names, so the renamer is order-independent and still breaks the shipped name. Any rule that looks only at the current document can resolve such a collision against the incumbent, whether it renames every member, orders by ID or orders by name. The only question is how often it happens.
What would deliver the promise
The incumbent has to be known, and only the prior generation knows it. docs/emitters/write-integrate.md already designs a prior manifest (EmitterInput.Prior, keyed by IR ID) for write/integrate. Collision resolution could consume it: a symbol the prior manifest assigns keeps its name, and only symbols new in this generation are disambiguated. Output stays a pure function of the inputs, because the prior manifest is an explicit input.
Two limits should be stated beside the fix:
- It holds only while the incumbent's IR ID is stable across revisions. Pointer-derived IDs change on rename (State the cross-revision identity answer: pointer IDs are stable within a document only #419).
- On a first run there is no prior manifest, so the within-document rule still applies. That rule should be deterministic and order-independent. The collision-set-wide renaming shown above is one way to meet both, and the two-order oracle is the test for it.
Acceptance
docs/emitters/refine/naming.mdnames the mechanism that backs the promise (the prior manifest), or narrows the promise to what ID-keying alone guarantees.- The mandatory tests (
docs/emitters/testing/mandatory-tests.md) gain a case: generate v1, add a colliding endpoint, regenerate against v1's manifest, and assert the v1 symbol is unchanged.
Activity
OmarAlJarrah commentedon Sep 30, 2026
A constraint on the fix: pin a prior symbol only when the IR ID and a key that survives reordering agree (#679). Where an ID contains an array index, the same ID can name a different entity in the next revision (#678); pinning by ID alone would give the new entity the old one's name. Pin only the disambiguation choice: a changed natural name, such as a renamed
operationId, should still rename.[-]docs/emitter-design: §4.12's stable-name promise needs the prior manifest[/-][+]docs/emitters: naming's stable-name promise needs the prior manifest[/+]docs(emitters): pin nothing for an entity without a correlation key