fix(figma): try the bridge before demanding a direct login - #60
Merged
Merged
Conversation
A collection asked the OAuth backend for a token before it asked anything whether a token was needed, and refused outright when there wasn't one. That inverted the two paths: the bridge spends no Figma allowance and needs no credential of any kind, while direct is metered and a single screen costs several reads. So whoever had attached the plugin - precisely to stay off the metered path - was told to go and authorize the metered path first, and the export never started, on a file every read of which the plugin was sitting there ready to serve. serves_without_credentials answers per file key rather than per process, because a plugin holding another file open says nothing about this one. The login is required only when no plugin is holding this file. A read the bridge genuinely cannot serve still refuses on its own, where the reason belongs to that read instead of condemning the whole export before it starts. devup_figma_auth doctor knew only about direct, which left the only instrument for diagnosing the connection able to give exactly one answer - run login - to every question, including the ones whose real answer was "run the plugin" or "the listener never bound". It now reports preferredPath and a paths.bridge block separating the three states that need three different repairs: not listening, listening with nothing attached, and attached with its file keys.
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
Reported from production: devup-mcp keeps demanding the direct connection even when the bridge plugin is attached and could serve the whole export. It does — and the demand happens before anything looks at the bridge.
start_operation_scoped_trackedasked the OAuth backend for a token before it asked anything whether a token was needed:That inverts the two paths. The bridge spends no Figma allowance and needs no credential of any kind; direct is metered and a single screen costs several reads. So whoever had attached the plugin — precisely to stay off the metered path — was told to go and authorize the metered path first, and the export never started, on a file every read of which the plugin was sitting there ready to serve.
After #57 moved node-scoped metadata onto the bridge, nothing in a tsx export needs the remote path at all. The collector only ever enqueues
metadata(bridged) andscreenshot(referencePngonly, opt-in) —VariableDefs/DesignContext/CodeConnectMapare never constructed on the collection path. So that refusal stood between an attached plugin and a finished screen for no remaining reason.Change
FigmaUpstream::serves_without_credentials(file_key)— defaultfalse,BridgeFigmaClientanswersstate.has_plugin(file_key),FallbackUpstreamdelegates. Per file key, not per process: a plugin holding another file open says nothing about this one.The login is now required only when no plugin is holding this file. A read the bridge genuinely cannot serve — a file-scope metadata read, or
referencePng'sget_screenshot— still refuses on its own, where the reason belongs to that read instead of condemning the whole export before it starts.The refusal, when it does fire, now offers the cheaper path first.
doctorknew only aboutdirectWhich left the only instrument for diagnosing the connection able to give exactly one answer — run
login— to every question, including the ones whose real answer was "run the plugin" or "the listener never bound". It now reportspreferredPath: "bridge"and apaths.bridgeblock separating the three states that need three different repairs:listening: falselistening: true, nothing attachedattachedFiles: [...]Evidence
Driven against the release binary over real stdio MCP with a real WebSocket plugin and no token stored at all:
The remaining error is the fake plugin declining the job, i.e. the export reached the read. Before this change the same call stopped at
DEVUP_AUTH_REQUIREDwithout reaching the bridge at all.Tests
source_orchestration::an_attached_bridge_collects_without_demanding_a_direct_login— new; verified failing before the change with exactly the production error.source_orchestration::auto_asks_to_be_logged_in_rather_than_starting_oauth— extended: the refusal has to offer the bridge first.bridge_transport::a_plugin_holding_the_file_makes_it_readable_without_credentials— new; per-file, so another file's plugin does not count.diagnostics::doctor_prefers_the_bridge_and_separates_its_three_states— new; also asserts a bridge problem is never answered withdevup_figma_auth.Gates
cargo fmt --all -- --checkcargo clippy --locked --workspace --all-targets --all-features -- -D warningscargo test --workspace --releasecargo build --release+--version+--self-check