Renaming the wire without breaking it
The problem
Renaming a project is mostly find-and-replace: the package, the import paths, the docs. We had already done that. What was left was the part that find-and-replace can't safely touch — the identifiers that leave the process and that someone else's code depends on by their exact spelling:
- the HMAC-signed webhook headers a receiver verifies *by name*,
- the MCP resource URIs an agent may have already listed and cached,
- the environment variables sitting in someone's CI config.
Rename any of these naively and you don't get a compile error. You get a silent breakage in production, in code you don't own. So the rule for this slice was: the new identifier is generated and preferred; the legacy one is still accepted and emitted alongside it; nothing breaks. Removal comes later, deliberately (tracked as T87), once integrations have migrated.
But "dual-emit everything" is the lazy answer. The three families carry very different risk, and that shaped how much each one was worth.
The high-risk one: signed webhook headers
A webhook receiver verifies authenticity by computing an HMAC over the payload and comparing it to the signature header. Crucially, it looks the signature up *by header name*. Rename X-Forge-Signature to X-Smeldr-Signature and every existing receiver fails verification — not with an error you'll see, but by silently rejecting (or worse, silently accepting) deliveries.
So the signature is computed once and sent under both names, with identical values:
// outbound.go — dual-emitted during the T86 deprecation window
req.Header.Set("X-Smeldr-Signature", sig)
req.Header.Set("X-Smeldr-Timestamp", strconv.FormatInt(ts, 10))
req.Header.Set("X-Smeldr-Event", job.Event)
req.Header.Set("X-Smeldr-Delivery", job.ID)
req.Header.Set("X-Forge-Signature", sig) // same value
req.Header.Set("X-Forge-Timestamp", strconv.FormatInt(ts, 10))
req.Header.Set("X-Forge-Event", job.Event)
req.Header.Set("X-Forge-Delivery", job.ID)
sig is the same sha256=<hex> string in both. An existing receiver keeps verifying X-Forge-Signature and never notices; a new one verifies X-Smeldr-Signature. This is the low-visibility, high-breakage corner — nobody sees these headers in a UI, but get it wrong and you break auth. It is the part of the sweep that was pure cost, done for completeness, not for value.
The low-risk one: MCP resource URIs
The opposite case. Every AI agent that browses resources sees the URI scheme, so it is highly visible — but it is also transient: an agent lists resources and reads one in the same breath, so a cached forge:// URI is rare and short-lived.
The new scheme is generated:
smeldr://posts/{slug}
and the parser accepts both, so any agent still holding a forge:// URI resolves fine:
// resource.go
// parseResourceURI resolves a smeldr:// or forge:// URI to its module and slug.
// Accepts the new smeldr:// scheme (preferred) and the legacy forge:// scheme
// (still accepted during the deprecation window — T87 removes it).
High visibility, low breakage: generate the new, accept both, move on. The MCP server also now identifies itself as smeldr-mcp in serverInfo — checked first that nothing keyed on the old name.
The boring one: environment variables
The CLI now prefers SMELDR_URL / SMELDR_TOKEN / SMELDR_MCP_URL and falls back to the FORGE_* names if only those are set; init writes a .smeldr-cli.env. Anyone's existing CI keeps working untouched; new setups use the Smeldr names.
The principle
Three families, one rule, calibrated by risk:
| Identifier | Visibility | Breakage risk | Treatment |
|---|---|---|---|
| Webhook HMAC headers | Low | High (verified by name) | dual-emit, identical values |
| MCP resource URIs | High | Low (transient) | generate new, accept both |
| CLI env vars | Low | Medium | prefer new, fall back to legacy |
In every case: the new identifier is generated and preferred, the legacy one is accepted/emitted alongside, and nothing breaks. The one thing that is *not* in this release is the removal — dropping forge://, ceasing to emit X-Forge-*, dropping the FORGE_* fallback. That is a deliberate, separately-communicated breaking change for later (T87), once the telemetry says integrations have moved. Renaming the wire is safe precisely because the rename and the removal are two different events, with a deprecation window in between.