Skip to content

Update Versions - #31

Open
github-actions[bot] wants to merge 1 commit into
mainfrom
changepacks/main
Open

Update Versions#31
github-actions[bot] wants to merge 1 commit into
mainfrom
changepacks/main

Conversation

@github-actions

@github-actions github-actions Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Changepacks

devup-mcp@0.4.5 → 0.5.0 - crates/devup-mcp/Cargo.toml

Minor

  • Extend the server past design projection into the rest of the DevFive lifecycle. Expose the existing pure-Rust PNG comparison as devup_visual_compare, where an unattested or invalid renderer environment makes the verdict inconclusive rather than a pass. Add devup_feature_trace, which turns caller-supplied anchors into a screen-to-API-to-route-to-model-to-column slice and refuses to read requirement prose as an anchor. Map route columns by parsing schema_type! pick and omit declarations instead of matching substrings, recognise the remaining devup-api call forms, and attach source ownership so a drift never proposes editing a generated artifact. Validate DevFive client-boundary, file-placement, export-shape, query-state and inline-style conventions from a bounded in-memory file bundle. Return ranked component reuse evidence under a project context ui scope that stays out of all. Fingerprint each design node over the fields the converter reads so a re-export can name what changed. Emit a preview-first page scaffold file set whose writes are opt-in and refuse collisions atomically through the existing rollback.
  • Stop painting words the design does not contain, parse route declarations instead of scanning for quotes, and let a re-export name what went stale. The text emitter no longer lets JSX insert a space where the design has none and no longer turns a design line break into a space; a 466-text sweep now round-trips every text node against a browser whitespace model, Unicode and non-breaking spaces survive, and the CSS collapse that no emission can avoid is reported as an explicit finding rather than silently painted. Vespera route attributes are parsed as Rust rather than matched with a quote scan, so a path inside a comment, a doc comment or an unrelated macro is no longer mistaken for a route, raw strings and multi-line attributes resolve, and a cfg-gated handler is reported conditionally instead of being claimed as present; unresolved files keep the old check under a separate lower-confidence kind and no finding is promoted above medium, because a successful parse is not proof of complete scanning. Design fingerprints can now be written as a guarded versioned sidecar and compared on a later export, returning unchanged, changed, added and removed nodes together with an explicit statement that a change means a converter input moved, not that the rendered screen changed and not that the code on disk still matches.
  • Make the generated screen stand where Figma draws it. Figma advances each line by round(fontSize * ratio) and the browser accumulates the fraction instead, so a percentage line height drifted a little on every line and compounded through hugging parents; the emitted advance is now the whole-pixel length rather than a ratio, and all seven measured text blocks match their design height exactly. Because a pixel advance is only valid for the size it was computed from, the resolved font size now travels with it, and a percentage line height whose font size is missing or bound to a mode-dependent variable is refused with a typed error naming the node or text style rather than emitted as a number that would be wrong at another size. The second half of the divergence was an inside stroke: Figma's inside stroke consumes no layout space, and the existing padding compensation cannot absorb a CSS border when the design's own padding is narrower than the stroke, so every bordered auto-layout container grew by twice its stroke weight and pushed the sections below it down. That case now paints inward with an outline at a negative offset, taking no layout space at all, and the padding compensation stands down for it; the choice keys on stroke alignment, layout mode, and stroke weight against padding, never on a viewport width, so it survives a design redrawn at another size. Source map and provenance follow the new emission: outline and outlineOffset carry their stroke provenance, and a rich-text wrapper's own advance is attributed to the segment whose text follows it. Twenty-four plugin goldens change, each enumerated with its reason in docs/line-box-displacement.md; the corpus consistency test and the manifest checksums are unchanged in force. Measured on the landing screen against Figma's own PNG, the three widths move from 11.41 / 3.10 / 1.84 percent to 4.99 / 2.47 / 1.50 percent, and the rendered height now equals the design height at all three.
  • Stop losing bold. A text node whose segments share a typography token can still override the weight per run, and both text emitters suppressed fontWeight whenever a token was present, so alternating 400/700 runs came out uniform. The token name carries no resolved metrics, so nothing downstream could recover them. Missing bold changes glyph advances and therefore wrapping, which is how a lost weight became a layout defect: on the about screens one 36px line wrapped that the design does not wrap, and every section below inherited the displacement. Emitting the resolved weight alongside the token brings the rendered page height to within one pixel of the design at both wider widths, from 37 pixels over, and the measured divergence from Figma's own PNG falls from 6.90 to 4.06 percent at 992 and from 4.19 to 2.41 percent at 1920, paid for by 0.02 percent at 360. Segment-sourced weights are attributed to styledTextSegments in the source map while explicit node weights keep their node-property mapping, so the provenance says which one actually supplied the number. Korean keeps word-break: keep-all. Removing it was implemented and measured because Figma breaks Korean within words and matching that narrows the pixel gap, but it narrows it by 0.21 percent on one screen while chopping every Korean word in every generated screen and breaking 38 attributes across 17 plugin byte-parity goldens; the pixel metric is a proxy for correctness and this is where the two disagree. Figma's Korean line breaking is a limitation to compensate for rather than a specification to reproduce, which is the same call the plugin makes in its own text renderer, and a test now locks the behaviour so a later fidelity pass cannot quietly reverse it. One golden changes, for a segment that explicitly carries weight 400.
  • Stop charging every session for guidance most callers never read, and report build staleness on the identity every response already carries. The twelve numbered rules move out of the initialize instructions, which drop from about 3,500 bytes to 951, into a pulled devup://guide/usage resource; rule numbering is preserved and a test asserts no rule was lost in the move, and shipping the text inside the binary keeps it from drifting the way a README can. server.updateAvailable reports whether a newer release exists, distinguishing disabled, not-yet-run, ran-and-could-not-tell and known, and only the last ever claims staleness. The lookup runs in a background task on a daily interval and the response path reads a cache, so no tool call performs a network request and none can be delayed by one; doctor and --self-check stay network-free because the task starts from the initialize handler rather than from server construction. DEVUP_MCP_NO_UPDATE_CHECK disables it. The server never downloads or replaces its own binary, which it could not do anyway while the MCP host owns its stdio pipes.

Patch

  • Stop failing a build-identity test for something that is not a defect. The test compared the -dirty suffix baked into the binary at compile time against a git status it ran itself at test time, which are two observations of the working tree taken at two different moments; an untracked file appearing in between, a probe script or a scratch log, made a correctly behaving binary report clean while the test's own git call reported dirty, and the assertion failed with no bug to find. It failed that way during the line-box investigation. The build script now publishes what it actually observed, DEVUP_MCP_GIT_DIRTY as true, false or unknown when git could not be asked, together with DEVUP_MCP_BUILD_ID_SOURCE recording whether the identity came from git or from an injected DEVUP_MCP_BUILD_ID, and the test asserts against those build-time facts instead. What stays under test is the chain that can actually break: the git observation, the suffix git_identity derives from it, and --version printing the baked value faithfully; an injected identity carries whatever suffix its caller chose and an unknown observation says nothing about this plumbing, so neither is asserted. The run-time comparison remains as a note on stderr, because a tree that moved between building and running is information about the run rather than a fault in the binary.

devup-mcp-devup-ui@0.4.5 → 0.5.0 - crates/devup-mcp-devup-ui/Cargo.toml

Minor

  • Stop cropping a photograph twice. A CROP image fill carries its framing as a matrix over the image's own coordinate space, and the generator read that matrix and turned it into a CSS background position and size. That would be right if the file being positioned were the original image, but it is not: the emitted file is a node export, and Figma has already applied the crop when producing those pixels. Applying the matrix again framed an already-framed picture, which is why the about page's photographs came out zoomed and offset against Figma's own render of the same frame - and why the earlier attempt to honour the crop appeared to help while measuring worse. A cropped fill now maps its exported frame once onto the layout box, and the matrix reader is deleted rather than left for someone to reach for again; FIT, FILL and TILE are unchanged. Measured against Figma's reference PNG, the three about screens improve from 7.46, 4.06 and 2.41 percent to 5.51, 3.01 and 1.77, with page heights unchanged and every other screen byte-identical. All 268 plugin byte-parity goldens are unchanged, and the responsive-screen expectation that asserted the old doubled crop is corrected to state why the export is mapped once.
  • Extend the server past design projection into the rest of the DevFive lifecycle. Expose the existing pure-Rust PNG comparison as devup_visual_compare, where an unattested or invalid renderer environment makes the verdict inconclusive rather than a pass. Add devup_feature_trace, which turns caller-supplied anchors into a screen-to-API-to-route-to-model-to-column slice and refuses to read requirement prose as an anchor. Map route columns by parsing schema_type! pick and omit declarations instead of matching substrings, recognise the remaining devup-api call forms, and attach source ownership so a drift never proposes editing a generated artifact. Validate DevFive client-boundary, file-placement, export-shape, query-state and inline-style conventions from a bounded in-memory file bundle. Return ranked component reuse evidence under a project context ui scope that stays out of all. Fingerprint each design node over the fields the converter reads so a re-export can name what changed. Emit a preview-first page scaffold file set whose writes are opt-in and refuse collisions atomically through the existing rollback.
  • Make the generated screen stand where Figma draws it. Figma advances each line by round(fontSize * ratio) and the browser accumulates the fraction instead, so a percentage line height drifted a little on every line and compounded through hugging parents; the emitted advance is now the whole-pixel length rather than a ratio, and all seven measured text blocks match their design height exactly. Because a pixel advance is only valid for the size it was computed from, the resolved font size now travels with it, and a percentage line height whose font size is missing or bound to a mode-dependent variable is refused with a typed error naming the node or text style rather than emitted as a number that would be wrong at another size. The second half of the divergence was an inside stroke: Figma's inside stroke consumes no layout space, and the existing padding compensation cannot absorb a CSS border when the design's own padding is narrower than the stroke, so every bordered auto-layout container grew by twice its stroke weight and pushed the sections below it down. That case now paints inward with an outline at a negative offset, taking no layout space at all, and the padding compensation stands down for it; the choice keys on stroke alignment, layout mode, and stroke weight against padding, never on a viewport width, so it survives a design redrawn at another size. Source map and provenance follow the new emission: outline and outlineOffset carry their stroke provenance, and a rich-text wrapper's own advance is attributed to the segment whose text follows it. Twenty-four plugin goldens change, each enumerated with its reason in docs/line-box-displacement.md; the corpus consistency test and the manifest checksums are unchanged in force. Measured on the landing screen against Figma's own PNG, the three widths move from 11.41 / 3.10 / 1.84 percent to 4.99 / 2.47 / 1.50 percent, and the rendered height now equals the design height at all three.
  • A single child is not distributed. Figma centers the only in-flow child of a SPACE_BETWEEN auto-layout; CSS flexbox has nothing to space between and parks that child at the start, so every such node was generated in the wrong place. The keyframes screen made it visible because it is 64 pixels across and built from single-dot wrappers: a 2px dot that Figma draws at x=5 inside a 12px box was drawn at x=0, and the same wrappers recur on the notice desktop frame. The emitter now reads the distribution as center when the layout is horizontal or vertical, the alignment is SPACE_BETWEEN, and exactly one child is both visible and not absolutely positioned, because hidden and absolute children take no part in distribution and must not be counted. The source map gains derived-lone-child-center rather than reusing an existing label, and its published description states which fields decide the count and that the mapping is a layout-semantics correspondence rather than a claim of pixel parity. Measured against Figma's reference PNG, keyframes falls from 6.71 to 2.69 percent and notice desktop from 2.20 to 1.88, with every other screen byte-identical and all 268 plugin byte-parity goldens unchanged. The investigation also retired a standing theory with evidence: the harness disables animations, so this screen's divergence was never the animation being caught mid-flight. The 110 pixels that remain are circle edges, and the report names fractional paint origins and edge coverage as the next lead rather than guessing at a cause.
  • Two layout defects on the notice screens, found the week the harness stopped hiding them. A horizontal row can overflow collectively even when every child fits on its own, and CSS min-width:auto then refuses to let a FILL sibling shrink to its share: a navigation item Figma draws at 95px expanded to 316px, pushed an address block onto three extra lines, and made the tablet page 72px taller than the design. The existing minW=0 rule already covered the case where a single child is wider than its parent; it now also covers the row that only overflows once its children are added together, still measured from the snapshot rather than assumed, still skipped when the design states its own minWidth, and applied only to non-wrapping horizontal rows because a wrapping row distributes that content over more lines instead. Separately, an SVG mask with an export offset was refused a folded layout size outright, so a social icon the design gives 82x32 was generated at zero width and everything below it shifted. The refusal exists because a FILL axis would scale the layout box while the pixel mask offsets stay where they are, and because a positioned or free-layout asset is placed from its export box; none of that applies to an in-flow HUG or FIXED axis, which keeps its measured box while maskSize and maskPos go on describing the larger painted bounds. Both conditions read node fields only - layout mode, wrap, sizing, positioning, and measured widths - so neither carries a viewport, a breakpoint, a node id, or a constant fitted to the current capture. Measured against Figma's own PNG, the three notice screens improve from 5.54 / 3.35 / 2.22 to 5.25 / 3.22 / 2.20 percent, the tablet page height falls from 72 pixels over the design to 3, and the other twelve screens are byte-identical. All 268 plugin byte-parity goldens are unchanged.
  • Stop losing bold. A text node whose segments share a typography token can still override the weight per run, and both text emitters suppressed fontWeight whenever a token was present, so alternating 400/700 runs came out uniform. The token name carries no resolved metrics, so nothing downstream could recover them. Missing bold changes glyph advances and therefore wrapping, which is how a lost weight became a layout defect: on the about screens one 36px line wrapped that the design does not wrap, and every section below inherited the displacement. Emitting the resolved weight alongside the token brings the rendered page height to within one pixel of the design at both wider widths, from 37 pixels over, and the measured divergence from Figma's own PNG falls from 6.90 to 4.06 percent at 992 and from 4.19 to 2.41 percent at 1920, paid for by 0.02 percent at 360. Segment-sourced weights are attributed to styledTextSegments in the source map while explicit node weights keep their node-property mapping, so the provenance says which one actually supplied the number. Korean keeps word-break: keep-all. Removing it was implemented and measured because Figma breaks Korean within words and matching that narrows the pixel gap, but it narrows it by 0.21 percent on one screen while chopping every Korean word in every generated screen and breaking 38 attributes across 17 plugin byte-parity goldens; the pixel metric is a proxy for correctness and this is where the two disagree. Figma's Korean line breaking is a limitation to compensate for rather than a specification to reproduce, which is the same call the plugin makes in its own text renderer, and a test now locks the behaviour so a later fidelity pass cannot quietly reverse it. One golden changes, for a segment that explicitly carries weight 400.

Patch

  • Stop painting words the design does not contain, parse route declarations instead of scanning for quotes, and let a re-export name what went stale. The text emitter no longer lets JSX insert a space where the design has none and no longer turns a design line break into a space; a 466-text sweep now round-trips every text node against a browser whitespace model, Unicode and non-breaking spaces survive, and the CSS collapse that no emission can avoid is reported as an explicit finding rather than silently painted. Vespera route attributes are parsed as Rust rather than matched with a quote scan, so a path inside a comment, a doc comment or an unrelated macro is no longer mistaken for a route, raw strings and multi-line attributes resolve, and a cfg-gated handler is reported conditionally instead of being claimed as present; unresolved files keep the old check under a separate lower-confidence kind and no finding is promoted above medium, because a successful parse is not proof of complete scanning. Design fingerprints can now be written as a guarded versioned sidecar and compared on a later export, returning unchanged, changed, added and removed nodes together with an explicit statement that a change means a converter input moved, not that the rendered screen changed and not that the code on disk still matches.

devup-mcp-visual@0.4.5 → 0.5.0 - crates/devup-mcp-visual/Cargo.toml

Minor

  • Extend the server past design projection into the rest of the DevFive lifecycle. Expose the existing pure-Rust PNG comparison as devup_visual_compare, where an unattested or invalid renderer environment makes the verdict inconclusive rather than a pass. Add devup_feature_trace, which turns caller-supplied anchors into a screen-to-API-to-route-to-model-to-column slice and refuses to read requirement prose as an anchor. Map route columns by parsing schema_type! pick and omit declarations instead of matching substrings, recognise the remaining devup-api call forms, and attach source ownership so a drift never proposes editing a generated artifact. Validate DevFive client-boundary, file-placement, export-shape, query-state and inline-style conventions from a bounded in-memory file bundle. Return ranked component reuse evidence under a project context ui scope that stays out of all. Fingerprint each design node over the fields the converter reads so a re-export can name what changed. Emit a preview-first page scaffold file set whose writes are opt-in and refuse collisions atomically through the existing rollback.

@github-actions
github-actions Bot force-pushed the changepacks/main branch 14 times, most recently from 6b71957 to 1923822 Compare September 13, 2026 05:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants