fix(runtime): derive shard and procedure ids from the declaration site - #253
Open
JuanMarchetto wants to merge 1 commit into
Open
fix(runtime): derive shard and procedure ids from the declaration site#253JuanMarchetto wants to merge 1 commit into
JuanMarchetto wants to merge 1 commit into
Conversation
`#[shard]` and `#[procedure]` minted their endpoint id with `Uuid::new_v4()` at expansion time, so every compile produced new URLs under /_topcoat/shards and /_topcoat/procedures. A tab left open across a deploy kept polling an id the new binary no longer served, and the runtime swapped in an empty body without an error. The macros now emit `module_path!()` into the generated code and hash it in the declaring crate, keyed by crate name, module path, and function name.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #252.
#[shard]and#[procedure]minted their endpoint id withUuid::new_v4()at macro expansion time, so every compilation produced new URLs under/_topcoat/shards/<id>and/_topcoat/procedures/<id>. A browser tab left open across a deploy keeps polling the previous binary's id, the new binary does not serve it, and the failure is silent: the runtime swaps the empty body in and the widget content disappears with nothing in the console.topcoat asset bundlecompiles the crate, so the bundling step can mint fresh ids partway through a deploy sequence.The macros now emit
module_path!()into the generated code and hash it in the declaring crate, the same shape asAssetId::newdoing its work at the declaration site. The key isCARGO_CRATE_NAME, the module path, and the function name, folded with the in-treefnv1aconst hash and rendered as 16 ASCII hex characters. Two items cannot share a name inside one module, so that key is collision-free for declarations at module scope, where hashing the source file would not be: two modules in one file can each hold a#[shard] fn rows. The derivation, the argument for it, and the check that it compiles and survives a rebuild are AmeinEskinder's, from his comment on #252.ShardIdandProcedureIdkeep their&'static strnewtype andconst fn new, and the route path still comes fromas_str. Nothing in the tree parses or validates the id shape: the two route builders interpolate it withformat!,ReactiveScopewrites it into the scope comment, and the browser runtime passes it throughencodeURIComponent. The id is 16 hex characters rather than a 36-character uuid, which no consumer notices.The tradeoff, stated plainly because it is a maintainer decision: a derived id makes a shard or procedure URL permanent across deploys, where today it changes on every build, so someone who records a URL keeps a working one instead of losing it at the next deploy. Shard endpoints need their own authorization either way, as the guards note from #251 says. If you want a different derivation, such as a per-deploy salt or an opt-in
#[shard(id = "...")]escape hatch, redirect me and I will redo it.Testing
Before, on
main, expandingexamples/shardtwice with only a comment changed between the two runs:After, the id is computed in the declaring crate, so it appears in the binary rather than in the expansion.
6aaf9450fdc57264isendpoint_id_hash("shard", "shard", "combobox_content"), and the same comment edit leaves it in place:examples/procedurebehaves the same way, serving82edc9c5c31a7706forprint_on_server.New tests:
crates/topcoat-runtime/src/id.rspins the id of a known crate, module, and name, so a change in the derivation fails loudly, and covers the module and crate separation plus the hex width. The shard and procedure grammars each gain a test that two expansions of one source are identical and that the id comes from crate, module, and name.Check gauntlet from
.agents/skills/check/SKILL.md:crates/topcoat-runtime/browseris untouched, sodist/index.jsis unchanged and the yarn steps do not apply.Disclaimer
Written with Claude Opus 5 in Claude Code. The agent located the defect, wrote the fix, and ran the checks; I reviewed the diff and the test output before opening this PR.