Repository navigation
feat(edge): mint an effect id for each module call - #58
Merged
Merged
Conversation
A module operation that keeps receipts (sdk-go/receipts, RECOVERY_RECEIPT) requires an x-codefly-effect-id on every call, and the edge forwards no x-codefly-* header a browser sent. So a browser could never reach a guarded operation: obin-ai/module-robin#633 found chat's rename would break for the UI the moment it is guarded. The edge now sets a fresh effect id (uuid) on each module call, after stripping the browser's x-codefly-* headers, and none on frontend calls. It stays within the edge's rule ("no x-codefly-* header leaves the edge unless the edge set it"), and since a browser never names an effect it can't replay another person's receipt: receipts are keyed by tenant, effect and method, not by person. Each call is its own effect, so a browser retry is a new attempt, as it is today. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The receipts SDK accepts Idempotency-Key as the HTTP spelling of the effect id. The edge kept it, so a caller sending one put two effect ids on the call, and both SDK adapters refuse that with InvalidArgument before the operation runs. Strip it whenever the edge mints the effect id; the test now sends one on REST and Connect and checks neither reaches the module. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
Author
|
Review finding fixed in 7a2439a: the edge now drops a caller's |
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.
What
The edge mints a fresh
x-codefly-effect-id(receipts.EffectIDHeaderName, a UUID) on every module call it forwards. It does this after stripping the browser'sx-codefly-*headers, and sets none on frontend calls.Why
A module operation that keeps receipts (Codefly
sdk-go/receipts,RECOVERY_RECEIPT) requires an effect id on every call. Its guard refuses a call without one. The edge forwards nox-codefly-*header a browser sent, so today a browser can never reach a receipt-guarded operation.Found in obin-ai/module-robin#633. To prove confirmed writes, Robin makes
RenameConversationrecoverable with the receipts SDK, and the chat UI's own rename would then be refused. Every receipt-guarded write a page calls hits the same wall.Why the edge mints it, rather than the browser sending one
x-codefly-*header leaves the edge unless the edge set it".Considered and not done: forwarding a browser-sent effect id. That would make UI retries safe, but it relaxes the edge's rule and needs receipts keyed by person.
Changes
edge.go:toModulemints the id,proxysets it after stripping; the frontend proxy passes none.effect_test.go(new): a forgedX-Codefly-Effect-Idis replaced, two calls get different ids, and the Connect face gets one too. It failed before the change ("the module received effect id """).environment_proxy_test.go: the new argument.go.mod/go.sum:sdk-gowas already required;receiptsbrings one indirect dependency (santhosh-tekuri/jsonschema/v6).Fix or hack
Fix at its owner: the edge owns which
x-codefly-*headers reach a module. Interfaces and conformance don't state edge header behaviour, so this isn't a contract change.Open: a production host's browser edge (Accounts / saas-starter auth-gateway) has to do the same, or a receipt-guarded write called from a page breaks there too. I didn't check that edge's header handling.
Checks
go vet .andgo test .inmodules/authority/services/edge/code: pass.🤖 Generated with Claude Code