refactor: narrow what devup-mcp asks for and what it sends back - #8
Merged
Conversation
Three things were costing every caller on every call: two tools that were one tool, a parameter that never branched, and a response that restated itself. Measured rather than guessed - a tsx-only export was 2,411 bytes of which 1,911 was carried regardless of what was asked for. ## Nine tools become seven `devup_figma_to_ui` and `devup_figma_to_json` were `devup_figma_export` with a single entry in `outputs`. Every client carried three schemas in its context and had to choose between them on each call, and the export tool's own description spent a sentence saying which to prefer. Use `outputs: ["tsx"]` and `outputs: ["devupJson"]`. Removing them also deletes ~190 lines from `complete_operation`, which had grown to just over a thousand. ## `sourcePolicy` is gone `auto` and `direct` both meant the direct connection; the parameter never branched. It offered a caller nothing but a chance to get it wrong, and it was part of the artifact cache key it could not affect. ## Closed sets are published in the schema `action`, `scope`, `rootLayout`, `delivery`, `match`, the project context `scope` and the stack diff `layers` all arrived as bare strings, so a caller learned the accepted values one rejection at a time. `outputs` and the asset `format` already published theirs, and the constant behind `outputs` says in its own doc comment that this is the point. Each set is now one constant that both the schema and the parser read, so the two cannot drift. ## A caller mistake is INVALID_PARAMS Every error reached the caller as `INTERNAL_ERROR`, so "you passed a scope this tool does not have" and "Figma stopped answering" were indistinguishable at the protocol level. For an agent that is the difference between fixing its arguments and giving up. A mistake in the call - an unknown scope, a node that is not in the file, an expired `artifactId` - is now `INVALID_PARAMS`; everything behind the call stays `INTERNAL_ERROR`. `data` carries the same `code` and `retryable` as before. Argument validation that had been reported as `DEVUP_THEME_CONFLICT` or `DEVUP_SNAPSHOT_UNSUPPORTED` is `DEVUP_INVALID_INPUT`, so a real theme conflict is no longer confused with a typo. ## The response stops restating itself A tsx-only export goes from 2,411 to 1,405 bytes, and the part carried regardless from 1,911 to 994. `fidelity` and `completenessReport` are the drill-down beneath `quality`; on a clean result they report 100% across six axes and six empty arrays, which `quality` already said. They are sent when the result is not exact or complete, and whenever `includeDiagnostics` asks for them. On a Section export that was per screen. `imports`, `usedTokens`, `componentImports`, `responsiveImports` and `responsiveComponents` restated the tsx's own first line and its `$token`s. `deliverable` existed to stop an agent mistaking a `needs_figma` handoff step for the answer, and that handoff no longer exists, so it was restating `status` in prose on every response. `completeness` and `themeCompleteness` stay: they grade how far token resolution reached, which `quality` does not say. `cache` stays whole - it is the artifact-reuse contract that avoids real Figma calls, and its fields are pinned by tests. The server instructions were the larger cost and are the larger fix. They told every agent to take `tsx`, `rawSnapshot` and `sourceMap` together; on the same measurement `sourceMap` is about 5x the size of the tsx it annotates and `rawSnapshot` about 2x, so following the instruction spent roughly eight bytes for every one of code. They now say to ask for an output only when it will be read, and what each one is for. ## Releases stop shipping devup-mcp-visual The render harness builds it from source with cargo and nothing downloads it, so three of six release assets were binaries no consumer had a use for, built on every platform of every release. The crate stays. ## Cargo.lock is committed at the released version It sat at 0.1.0 while the workspace moved to 0.2.1, so every build regenerated it, dirtied the tree, and made every release binary report its build id as `1e8b0b6de9a6-dirty` - which meant `--version` and `--self-check` could not tell a release from a developer's working tree, the one thing they exist to do. ## Also Removes `DevupFigmaHostRequired` and `DevupCompatCorpusDrift`, which no production code ever constructed. Their only reference was a test pinning their wire strings, which would have passed forever whether or not they were reachable; that test is replaced by one that pins the INVALID_PARAMS split on both sides.
…iverable Two corrections from consumer feedback on the previous commit. ## A lost token is no longer silent A fill bound to a variable, or a text carrying a style, is the design saying "this is a token". The generator writes the token when the resource catalog carried that variable or style, and the resolved value when it did not. Writing something is right - the module still has to compile and render. Writing it silently is not. Measured on a synthetic frame bound to `VariableID:1:1009` and `S:ddba35e8…` with neither in the catalog: the code came out with `#7d7f83` and `fontSize="14px" fontWeight="400" lineHeight="1.6"`, and `diagnostics` was empty. That value renders identically today and stops following the theme tomorrow, and the response still graded the conversion `exact`, so a caller reading only the answer had no way to know a token was in there. The report a consumer had to reach for instead was `sourceMap`, which is about five times the size of the tsx it annotates. Each such binding now raises `DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED` carrying the node, the property and the resource id. Being a `DEVUP_CODEGEN_` warning it counts as an approximation, so `quality.projection` stops reading `exact` when a token was lost. The check is a pass over the collected subtree rather than a step inside rendering, so it can name the node a binding belongs to without threading an argument through every render function. The generated bytes do not change, so all 268 plugin-parity goldens are untouched. The path that already worked is pinned alongside it: with the catalog present, the same frame emits `$caption` and `typography="captionSm"`, no resolved value survives beside the token that names it, and nothing is reported. ## `deliverable` comes back It was removed on the reasoning that it only restated `status`, since the `needs_figma` handoff it originally guarded against no longer exists. A consumer reported relying on it: `status: "complete"` says the run went well, and `deliverable` says which of the response's values is the answer to implement from. That is a different sentence, and 109 bytes is cheap for it.
Contributor
Changepacksdevup-mcp@0.2.1 → 0.3.0 - crates/devup-mcp/Cargo.tomlMinor
devup-mcp-devup-ui@0.2.1 → 0.3.0 - crates/devup-mcp-devup-ui/Cargo.tomlMinor
devup-mcp-figma@0.2.1 → 0.3.0 - crates/devup-mcp-figma/Cargo.tomlMinor
devup-mcp-visual@0.2.1 → 0.2.2 - crates/devup-mcp-visual/Cargo.tomlPatch
|
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.
See the two commit messages for the full reasoning. Summary:
Tools 9 -> 7.
devup_figma_to_uianddevup_figma_to_jsonweredevup_figma_exportwith one entry inoutputs. Every client carried three schemas and had to choose between them on each call.sourcePolicyremoved.autoanddirectboth meant the direct connection; it never branched, and it was part of a cache key it could not affect.Closed sets published in the schema.
action,scope,rootLayout,delivery,match, project-contextscope, stack-difflayers- one shared constant read by both the schema and the parser.Caller mistakes are
INVALID_PARAMS. Everything used to arrive asINTERNAL_ERROR, so "you passed a scope this tool does not have" and "Figma stopped answering" were indistinguishable at the protocol level.Response stops restating itself. Measured: a tsx-only export 2,411 -> 1,405 B; the part carried regardless 1,911 -> 994 B.
fidelity/completenessReportare sent when they disagree with a clean grade or whenincludeDiagnosticsasks.deliverablestays - a consumer relies on it.A lost token is no longer silent. A binding whose variable/style the catalog never named was resolved to a raw value with nothing reported, inside a response graded
exact. It now raisesDEVUP_CODEGEN_TOKEN_NAME_UNRESOLVEDand stopsquality.projectionreadingexact. Generated bytes unchanged; 268 plugin goldens untouched.Releases stop shipping
devup-mcp-visual(harness builds it from source; nothing downloads it), andCargo.lockis committed at the released version, which stops every release binary reporting its build id as-dirty.