diff --git a/.changepacks/changepack_log_integration_0_4_6.json b/.changepacks/changepack_log_integration_0_4_6.json new file mode 100644 index 0000000..905f7ed --- /dev/null +++ b/.changepacks/changepack_log_integration_0_4_6.json @@ -0,0 +1,9 @@ +{ + "changes": { + "crates/devup-mcp-devup-ui/Cargo.toml": "Minor", + "crates/devup-mcp-figma/Cargo.toml": "Minor", + "crates/devup-mcp/Cargo.toml": "Minor" + }, + "note": "The 0.4.6 line, landed on main at last. R20 audits what still stands between the generator and a browser-measured claim, naming each remaining approximation rather than leaving the gap implicit. F1-F5 and F7 carry the responsive and project-context corrections: prevalidating a responsive export before it is projected, discovering breakpoint widths from the frames rather than assuming them, reconciling exported tokens against the theme a project already has, categorising token suggestions so an unmatched value is not advised toward a token that does not exist, budgeting a Section preview so a large selection cannot exhaust the projection, covering FILL layout where it was previously approximated, and reporting a typography token the validator had never been checking. F8 teaches devup-ui semantics to the caller and delivers skills through the CLI. The branch had never passed CI: ten rustfmt violations rode along with it, and they are fixed here rather than carried further. The bridge plugin's committed bundle is rebuilt because explore.js and section_index.js changed, and those scripts are compiled into the plugin - which is precisely the drift the new bundle gate exists to catch, and did.", + "date": "2026-09-14T00:30:00+09:00" +} diff --git a/Cargo.lock b/Cargo.lock index 23af185..a26ebf5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -693,7 +693,7 @@ checksum = "4583a4551df46e2792f82ceeac45e850d2e2d5debba0b91f102385cda5b11f06" [[package]] name = "devup-mcp" -version = "0.4.5" +version = "0.4.6" dependencies = [ "anyhow", "async-trait", @@ -722,7 +722,7 @@ dependencies = [ [[package]] name = "devup-mcp-devup-ui" -version = "0.4.5" +version = "0.4.6" dependencies = [ "devup-mcp-figma", "insta", @@ -739,7 +739,7 @@ dependencies = [ [[package]] name = "devup-mcp-figma" -version = "0.4.5" +version = "0.4.6" dependencies = [ "anyhow", "async-trait", @@ -766,7 +766,7 @@ dependencies = [ [[package]] name = "devup-mcp-visual" -version = "0.4.5" +version = "0.4.6" dependencies = [ "anyhow", "image", diff --git a/Cargo.toml b/Cargo.toml index a570383..faea5f3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ members = [ resolver = "3" [workspace.package] -version = "0.4.5" +version = "0.4.6" edition = "2024" rust-version = "1.98" license = "MIT" diff --git a/crates/devup-mcp-devup-ui/src/codegen/responsive.rs b/crates/devup-mcp-devup-ui/src/codegen/responsive.rs index dc36b6f..d7ce137 100644 --- a/crates/devup-mcp-devup-ui/src/codegen/responsive.rs +++ b/crates/devup-mcp-devup-ui/src/codegen/responsive.rs @@ -274,6 +274,70 @@ fn rank_of(name: &str) -> Option { BREAKPOINT_NAMES.iter().position(|known| *known == name) } +/// Whether roots with these names and widths could be a breakpoint family. +/// +/// The question [`breakpoints`] answers, asked without a snapshot, so it can +/// be put to a Section index — which already carries every candidate's name +/// and width — before anything is collected. +/// +/// It has to be answerable there. The refusal lived in projection, which runs +/// after the collection it needs: asking for `responsiveTsx` over two frames +/// of one Braillify Studio screen spent 77 seconds and ten Figma reads before +/// reporting that the snapshot had no mergeable breakpoint frames — a verdict +/// the frames' own names and widths settle in full. +/// +/// Keep this in step with [`breakpoints`]. `the_predicate_agrees_with_ +/// discovery` in `tests/responsive_prevalidate.rs` holds the two together, so +/// a change to either rule that forgets the other fails there rather than in +/// a 77-second export. +pub fn breakpoint_family_is_possible(frames: &[(&str, f64)]) -> bool { + let mut ranks: Vec = Vec::new(); + for (name, _width) in frames { + let Some(rank) = rank_of(name) else { + continue; + }; + if ranks.contains(&rank) { + continue; + } + ranks.push(rank); + } + if ranks.len() >= 2 { + return true; + } + width_family_is_possible(frames) +} + +/// The fallback [`breakpoints_by_width`] applies, asked of names and widths +/// alone: one name across two or more distinct width bands. +/// +/// Its two refusals are kept exactly, because either one loosened here would +/// let a collection start that the projection then refuses — the cost this +/// predicate exists to avoid. +fn width_family_is_possible(frames: &[(&str, f64)]) -> bool { + let mut shared_name: Option = None; + let mut slots: Vec = Vec::new(); + for (name, width) in frames { + let name = name.trim().to_ascii_lowercase(); + if *shared_name.get_or_insert_with(|| name.clone()) != name { + return false; + } + if *width <= 0.0 { + return false; + } + #[expect( + clippy::cast_possible_truncation, + clippy::cast_sign_loss, + reason = "a frame is a small positive number of pixels wide" + )] + let slot = slot_of_width(*width as u32); + if slots.contains(&slot) { + return false; + } + slots.push(slot); + } + slots.len() >= 2 +} + /// The breakpoint roots this snapshot carries, in the order the Section holds /// them. /// @@ -306,6 +370,67 @@ pub fn breakpoints(snapshot: &Snapshot) -> Vec { node_id: id.clone(), }); } + if found.len() < 2 { + return breakpoints_by_width(snapshot); + } + found +} + +/// The same screen drawn at several widths, for a file that does not use the +/// plugin's breakpoint names. +/// +/// `slot_of_width` already places a width "by how wide it is, not by what its +/// frame is called", but discovery read the name alone, so a file naming its +/// frames anything else had no family at all: Braillify Studio draws `AUTH-01` +/// at 1920 and again at 375, both directly under one Section, and asking for +/// `responsiveTsx` over the two answered that there was nothing to merge. +/// +/// Two conditions keep this from folding things the design never drew, and +/// either one failing leaves the snapshot with no family rather than a +/// guessed one: +/// +/// - **One name.** `AUTH-01` and `AUTH-02` are two designs, not one design at +/// two sizes. +/// - **Distinct width bands.** The same screen appears twice at 375 — a light +/// and a dark rendering — and neither is a breakpoint of the other. A band +/// claimed twice is ambiguous, and guessing which copy wins is the failure +/// this is meant to avoid. +/// +/// The roots keep the order the snapshot carries them in, for the reason +/// [`breakpoints`] documents: the first width that draws a node supplies the +/// widths that do not, and sorting changes which one that is. +fn breakpoints_by_width(snapshot: &Snapshot) -> Vec { + let mut shared_name: Option = None; + let mut found: Vec = Vec::new(); + for id in &snapshot.roots { + let Some(node) = snapshot.nodes.get(id) else { + return Vec::new(); + }; + let view = node.typed_view(); + let (Some(name), Some(width)) = (view.name(), view.number("width")) else { + return Vec::new(); + }; + let name = name.trim().to_ascii_lowercase(); + if *shared_name.get_or_insert_with(|| name.clone()) != name { + return Vec::new(); + } + if width <= 0.0 { + return Vec::new(); + } + #[expect( + clippy::cast_possible_truncation, + clippy::cast_sign_loss, + reason = "a frame is a small positive number of pixels wide" + )] + let slot = slot_of_width(width as u32); + if found.iter().any(|breakpoint| breakpoint.rank == slot) { + return Vec::new(); + } + found.push(Breakpoint { + rank: slot, + node_id: id.clone(), + }); + } if found.len() < 2 { return Vec::new(); } diff --git a/crates/devup-mcp-devup-ui/src/ui_validate.rs b/crates/devup-mcp-devup-ui/src/ui_validate.rs index e53c055..b892be1 100644 --- a/crates/devup-mcp-devup-ui/src/ui_validate.rs +++ b/crates/devup-mcp-devup-ui/src/ui_validate.rs @@ -49,7 +49,7 @@ use crate::style_props::{ DEVUP_PRIMITIVE_ELEMENTS, is_color_like_prop, is_known_non_style_prop, is_known_style_prop, is_length_like_prop, }; -use crate::theme::{ProjectTheme, closest_tokens}; +use crate::theme::{ProjectTheme, TokenCategory, closest_tokens}; /// Devup-ui `css`/`globalCss`/`keyframes` utility call names whose object /// argument must be statically analyzable (devup-ui's own @@ -256,7 +256,12 @@ impl<'t> TsxVisitor<'t> { && !theme.contains_token(token) { let catalog = theme.token_catalog(); - let names = catalog.keys().collect::>(); + let expected = token_category_for_prop(prop_name); + let names = catalog + .iter() + .filter(|(_, entry)| expected.is_none_or(|category| entry.category == category)) + .map(|(name, _)| name) + .collect::>(); let suggestions = closest_tokens(token, names.into_iter(), 3); self.violations.push(Violation { rule: "unknown-token", @@ -280,6 +285,43 @@ impl<'t> TsxVisitor<'t> { } return; } + // devup-ui's `typography` prop names a theme token without a `$`, so + // the check above never sees one. A generated Braillify Studio screen + // carried `typography="mainSubText"`, `"titleSmMed"` and `"bodyMed"`, + // none of them in that project's devup.json, and validation reported + // six unknown tokens — every one a color — while these three passed. + // An unknown typography token is a style that silently does not apply. + if prop_name == "typography" { + let Some(theme) = self.theme else { + return; + }; + // Nothing to check against, and a check that cannot be made is + // skipped rather than guessed, as it is for an absent theme. + if theme.typography.is_empty() { + return; + } + self.checked_tokens += 1; + if theme.typography.contains_key(text) { + return; + } + let suggestions = closest_tokens(text, theme.typography.keys(), 3); + self.violations.push(Violation { + rule: "unknown-token", + severity: Severity::Error, + context: Default::default(), + byte_range: [span.start as usize, span.end as usize], + message: format!("{text} is not a typography token in devup.json."), + suggestion: if suggestions.is_empty() { + None + } else { + Some(format!( + "closest existing typography tokens: {}", + suggestions.join(", ") + )) + }, + }); + return; + } if is_color_like_prop(prop_name) && is_hex_color(text) { let tokens = self .theme @@ -542,6 +584,30 @@ fn is_static_expression(expression: &Expression, conditional_classes: bool) -> b } } +/// Which category a `$token` written in this prop could belong to. +/// +/// A prop admits one kind of token, so only that kind can replace a name +/// the theme does not have. Ranking the whole catalog by edit distance +/// ignores that and answers a color prop with whatever is spelled closest: +/// `bg="$background"` came back as `$bodyStrong, $button, $caption`, three +/// typography tokens, while `$bg` — the color the project defines for +/// exactly this — was never offered. +/// +/// `None` for a prop this validator does not model. The whole catalog is +/// ranked then, as before: a worse suggestion is still better than none, +/// and narrowing on a guess would be the same mistake in reverse. +fn token_category_for_prop(prop_name: &str) -> Option { + if is_color_like_prop(prop_name) { + Some(TokenCategory::Colors) + } else if is_length_like_prop(prop_name) { + Some(TokenCategory::Length) + } else if matches!(prop_name, "boxShadow" | "textShadow") { + Some(TokenCategory::Shadow) + } else { + None + } +} + fn is_hex_color(text: &str) -> bool { let Some(hex) = text.strip_prefix('#') else { return false; @@ -616,6 +682,171 @@ mod tests { assert_eq!(report.checked_tokens, 1); } + /// A real project's `devup.json` (`braillify-studio` `apps/front`): colors + /// and typography side by side, where the color the generator wanted is + /// one edit away under a different name. + fn theme_with_colors_and_typography() -> ProjectTheme { + parse_project_theme( + r##"{ "theme": { + "colors": { "light": { + "bg": "#FFFFFF", "border": "#E5E5E5", + "text": "#111111", "textSubtle": "#9A9A9A" + } }, + "typography": { + "bodyStrong": { "fontSize": "14px" }, + "button": { "fontSize": "15px" }, + "caption": { "fontSize": "12px" } + }, + "length": {}, "shadow": {} + } }"##, + ) + .unwrap() + } + + /// A token named in a color prop can only be replaced by a color token. + /// Ranking the whole catalog by edit distance answered `bg="$background"` + /// with `$bodyStrong, $button, $caption` — three typography tokens, none + /// of which is usable here — while `$bg`, the one the project actually + /// defines for this, did not appear at all. + #[test] + fn unknown_color_token_is_never_advised_to_use_a_typography_token() { + let tsx = r##"export const X = () => ;"##; + let report = validate_devup_ui_tsx(tsx, Some(&theme_with_colors_and_typography()), false); + let violation = report + .violations + .iter() + .find(|violation| violation.rule == "unknown-token") + .expect("unknown-token violation"); + let suggestion = violation + .suggestion + .as_deref() + .expect("a theme with color tokens can always advise one"); + for typography in ["$bodyStrong", "$button", "$caption"] { + assert!( + !suggestion.contains(typography), + "{typography} cannot be used in a color prop: {suggestion}" + ); + } + assert!( + suggestion.contains("$bg"), + "the color token this project defines must be offered: {suggestion}" + ); + } + + /// The same rule in the other direction: a length prop is advised with + /// length tokens, never with the colors that happen to be spelled alike. + #[test] + fn unknown_length_token_is_advised_only_with_length_tokens() { + let theme = parse_project_theme( + r##"{ "theme": { + "colors": { "default": { "gutterColor": "#FFFFFF" } }, + "typography": {}, + "length": { "default": { "gutter": "16px" } }, + "shadow": {} + } }"##, + ) + .unwrap(); + let tsx = r##"export const X = () => ;"##; + let report = validate_devup_ui_tsx(tsx, Some(&theme), false); + let violation = report + .violations + .iter() + .find(|violation| violation.rule == "unknown-token") + .expect("unknown-token violation"); + let suggestion = violation.suggestion.as_deref().expect("length advice"); + assert!( + !suggestion.contains("$gutterColor"), + "a color token cannot be used in a length prop: {suggestion}" + ); + assert!( + suggestion.contains("$gutter"), + "the length token this project defines must be offered: {suggestion}" + ); + } + + /// A theme that names its typography, as every real one does. + fn theme_with_typography() -> ProjectTheme { + parse_project_theme( + r##"{ "theme": { + "colors": { "default": { "text": "#111111" } }, + "typography": { + "body": { "fontSize": "14px" }, + "bodyL": { "fontSize": "16px" }, + "h1": { "fontSize": "36px" } + }, + "length": {}, "shadow": {} + } }"##, + ) + .unwrap() + } + + /// devup-ui's `typography` prop names a theme token without a `$`, so the + /// `$`-prefixed check never saw one. A generated Braillify Studio screen + /// carried `typography="mainSubText"`, `"titleSmMed"` and `"bodyMed"` — + /// none of them in that project's devup.json — and validation reported + /// six unknown tokens, every one of them a color, and said nothing about + /// these three. An unknown typography token is a style that silently does + /// not apply. + #[test] + fn an_unknown_typography_token_is_reported() { + let tsx = r##"export const X = () => ;"##; + let report = validate_devup_ui_tsx(tsx, Some(&theme_with_typography()), false); + let violation = report + .violations + .iter() + .find(|violation| violation.rule == "unknown-token") + .unwrap_or_else(|| panic!("mainSubText is not in the theme: {:?}", report.violations)); + assert_eq!(violation.severity, Severity::Error); + assert!(violation.message.contains("mainSubText"), "{violation:?}"); + assert!(!report.ok); + } + + /// The advice for one names the others, and only the others. + #[test] + fn an_unknown_typography_token_is_advised_with_typography_tokens() { + let tsx = r##"export const X = () => ;"##; + let report = validate_devup_ui_tsx(tsx, Some(&theme_with_typography()), false); + let violation = report + .violations + .iter() + .find(|violation| violation.rule == "unknown-token") + .expect("bodyMed is not in the theme"); + let suggestion = violation.suggestion.as_deref().expect("typography advice"); + assert!(suggestion.contains("body"), "{suggestion}"); + assert!( + !suggestion.contains("$text"), + "a color cannot be a typography token: {suggestion}" + ); + } + + /// A token the theme does define is not flagged, and is counted as checked. + #[test] + fn a_defined_typography_token_passes() { + let tsx = r##"export const X = () => ;"##; + let report = validate_devup_ui_tsx(tsx, Some(&theme_with_typography()), false); + assert!(report.ok, "{:?}", report.violations); + assert_eq!(report.checked_tokens, 1); + } + + /// With no typography in the theme there is nothing to check against, and + /// a check that cannot be made is skipped rather than guessed — the rule + /// `a_theme_with_no_length_tokens_is_never_told_to_use_one` already holds + /// for lengths. + #[test] + fn a_theme_with_no_typography_tokens_flags_nothing() { + let tsx = r##"export const X = () => ;"##; + let report = validate_devup_ui_tsx(tsx, Some(&fixture_theme()), false); + assert!(report.ok, "{:?}", report.violations); + assert!( + report + .violations + .iter() + .all(|violation| violation.rule != "unknown-token"), + "{:?}", + report.violations + ); + } + #[test] fn flags_hardcoded_hex_color_with_suggestion() { let tsx = r##"export const X = () => ;"##; diff --git a/crates/devup-mcp-devup-ui/tests/responsive_discovery.rs b/crates/devup-mcp-devup-ui/tests/responsive_discovery.rs new file mode 100644 index 0000000..a361b2c --- /dev/null +++ b/crates/devup-mcp-devup-ui/tests/responsive_discovery.rs @@ -0,0 +1,110 @@ +//! Which roots count as the same screen drawn at several widths. +//! +//! The plugin names a breakpoint family `mobile` / `tablet` / `desktop`, and +//! discovery read those names. A file that does not use them — Braillify +//! Studio draws `AUTH-01` at 1920 and again at 375, both directly under the +//! `로그인 화면` Section — had no family at all, and asking for `responsiveTsx` +//! over the two frames answered "no mergeable breakpoint frames". +//! +//! The widths are already placed by size: `slot_of_width` is documented "a +//! width is placed by how wide it is, not by what its frame is called". These +//! fix discovery to agree with that, without letting unrelated frames merge. + +use devup_mcp_devup_ui::codegen::{CodegenOptions, responsive::merge_breakpoints}; +use devup_mcp_figma::Snapshot; +use serde_json::json; + +/// A snapshot whose roots are the given `(id, name, width)` frames. +fn snapshot(frames: &[(&str, &str, f64)]) -> Snapshot { + let nodes = frames + .iter() + .map(|(id, name, width)| { + ( + (*id).to_owned(), + json!({ + "id": id, + "type": "FRAME", + "fields": { + "name": name, + "width": width, + "height": 812.0, + "layoutMode": "VERTICAL", + "childrenIds": [], + }, + }), + ) + }) + .collect::>(); + serde_json::from_value(json!({ + "fileKey": "qFil2x88O3JOIzWNuXEE0M", + "version": null, + "roots": frames.iter().map(|(id, _, _)| *id).collect::>(), + "nodes": nodes, + "diagnostics": [], + })) + .expect("fixture snapshot") +} + +fn merged_slots(frames: &[(&str, &str, f64)]) -> Option> { + merge_breakpoints(&snapshot(frames), &CodegenOptions::default()) + .expect("merge must not error") + .map(|merged| merged.slots) +} + +/// The reported case: one screen, two widths, a name the plugin does not use. +#[test] +fn one_name_at_two_widths_is_a_breakpoint_family() { + let slots = merged_slots(&[ + ("777:510", "AUTH-01", 1920.0), + ("789:1425", "AUTH-01", 375.0), + ]) + .expect("1920 and 375 of one screen are a family"); + assert_eq!(slots, vec![0, 4], "375 is slot 0 and 1920 is slot 4"); +} + +/// The plugin's own naming keeps working and still ranks by width. +#[test] +fn the_plugin_breakpoint_names_still_merge() { + let slots = merged_slots(&[ + ("1:1", "mobile", 360.0), + ("1:2", "tablet", 992.0), + ("1:3", "desktop", 1920.0), + ]) + .expect("the plugin family merges as before"); + assert_eq!(slots, vec![0, 2, 4]); +} + +/// Two frames of one name at one width are not two widths. Braillify Studio +/// draws `AUTH-01` at 375 twice — the light and the dark rendering — and +/// folding one onto the other would claim a breakpoint the design never drew. +#[test] +fn one_name_twice_at_one_width_is_not_a_family() { + assert_eq!( + merged_slots(&[ + ("789:1425", "AUTH-01", 375.0), + ("789:1491", "AUTH-01", 375.0) + ]), + None, + "same width, so there is no second breakpoint" + ); +} + +/// Different screens are never folded together, however their widths differ. +/// `AUTH-01` and `AUTH-02` are two designs, not one design at two sizes. +#[test] +fn different_names_are_never_merged_on_width_alone() { + assert_eq!( + merged_slots(&[ + ("777:510", "AUTH-01", 1920.0), + ("789:1540", "AUTH-02", 375.0) + ]), + None, + "unrelated screens must not merge" + ); +} + +/// A single root is a screen, not a screen that changes. +#[test] +fn a_lone_frame_is_not_a_family() { + assert_eq!(merged_slots(&[("777:510", "AUTH-01", 1920.0)]), None); +} diff --git a/crates/devup-mcp-devup-ui/tests/responsive_prevalidate.rs b/crates/devup-mcp-devup-ui/tests/responsive_prevalidate.rs new file mode 100644 index 0000000..de55f86 --- /dev/null +++ b/crates/devup-mcp-devup-ui/tests/responsive_prevalidate.rs @@ -0,0 +1,87 @@ +//! Deciding a breakpoint family without collecting one. +//! +//! `responsiveTsx` was refused inside projection, which runs only after the +//! collection it needs. Two frames of one Braillify Studio screen spent 77 +//! seconds and ten Figma reads to be told the snapshot had no mergeable +//! breakpoint frames — a verdict their names and widths settle on their own, +//! and a Section index carries both for every candidate it lists. +//! +//! So the rule has to be answerable twice, and the two answers have to agree. + +use devup_mcp_devup_ui::codegen::responsive::{breakpoint_family_is_possible, breakpoints}; +use devup_mcp_figma::Snapshot; +use serde_json::json; + +fn snapshot(frames: &[(&str, f64)]) -> Snapshot { + let nodes = frames + .iter() + .enumerate() + .map(|(position, (name, width))| { + let id = format!("1:{position}"); + ( + id.clone(), + json!({ + "id": id, + "type": "FRAME", + "fields": { + "name": name, + "width": width, + "height": 812.0, + "layoutMode": "VERTICAL", + "childrenIds": [], + }, + }), + ) + }) + .collect::>(); + serde_json::from_value(json!({ + "fileKey": "qFil2x88O3JOIzWNuXEE0M", + "version": null, + "roots": (0..frames.len()).map(|i| format!("1:{i}")).collect::>(), + "nodes": nodes, + "diagnostics": [], + })) + .expect("fixture snapshot") +} + +/// Every selection the two can disagree about, and the assertion that they do +/// not. This is what keeps the cheap answer honest: a rule changed on one +/// side and not the other fails here, in milliseconds, instead of in an +/// export that collected first and refused afterwards. +#[test] +fn the_predicate_agrees_with_discovery() { + let selections: [Vec<(&str, f64)>; 8] = [ + // The reported case: one screen, two widths, a name the plugin does + // not use. + vec![("AUTH-01", 1920.0), ("AUTH-01", 375.0)], + // The plugin's own family. + vec![("mobile", 360.0), ("tablet", 992.0), ("desktop", 1920.0)], + vec![("mobile", 360.0), ("desktop", 1920.0)], + // One width is a screen, not a screen that changes. + vec![("mobile", 360.0)], + vec![("AUTH-01", 1920.0)], + // One name twice is still one width. + vec![("mobile", 360.0), ("mobile", 375.0)], + // Unrelated screens. + vec![("AUTH-01", 1920.0), ("AUTH-02", 375.0)], + vec![], + ]; + for frames in selections { + assert_eq!( + breakpoint_family_is_possible(&frames), + !breakpoints(&snapshot(&frames)).is_empty(), + "the two rules disagree about {frames:?}" + ); + } +} + +/// The predicate reads names and widths only, so a Section index answers it +/// as well as a snapshot does — which is the whole point of having it. +#[test] +fn the_plugin_family_is_recognized_from_names_and_widths_alone() { + assert!(breakpoint_family_is_possible(&[ + ("mobile", 360.0), + ("desktop", 1920.0) + ])); + assert!(!breakpoint_family_is_possible(&[("desktop", 1920.0)])); +} diff --git a/crates/devup-mcp-figma/src/scripts/explore.js b/crates/devup-mcp-figma/src/scripts/explore.js index 746f463..15f6d38 100644 --- a/crates/devup-mcp-figma/src/scripts/explore.js +++ b/crates/devup-mcp-figma/src/scripts/explore.js @@ -286,18 +286,30 @@ if (JSON.stringify(output).length > MAX_PROJECTION_JSON_CHARS) { // preview over the envelope cap or evict a candidate. let previewBudget = MAX_PROJECTION_JSON_CHARS - JSON.stringify(output).length; if (textPreviewLimit > 0 && previewBudget > 0) { - for (const projected of output.nodes) { - const source = included.get(projected.id); - if (!source || projected.id === page.id) continue; + // Each candidate takes an equal share of what is left rather than as much + // as it wants, so the last one is funded before the first is indulged. + // Spending the budget first-come left the tail with nothing at all, and a + // candidate with no text is one the caller cannot tell from its + // neighbours — which is the only thing a preview is for. What a candidate + // does not spend stays in the budget and widens the shares after it. + const fundable = output.nodes.filter( + (projected) => included.get(projected.id) && projected.id !== page.id, + ); + let unfunded = fundable.length; + for (const projected of fundable) { + const share = Math.floor(previewBudget / unfunded); + unfunded -= 1; + if (share <= 0) continue; let preview = ""; - for (const character of textPreview(source.node)) { + let spent = 0; + for (const character of textPreview(included.get(projected.id).node)) { const cost = JSON.stringify(character).length - 2; - if (cost > previewBudget) break; + if (spent + cost > share) break; preview += character; - previewBudget -= cost; + spent += cost; } projected.fields.textPreview = preview; - if (previewBudget === 0) break; + previewBudget -= spent; } } diff --git a/crates/devup-mcp-figma/src/scripts/section_index.js b/crates/devup-mcp-figma/src/scripts/section_index.js index e649f5e..5aecc83 100644 --- a/crates/devup-mcp-figma/src/scripts/section_index.js +++ b/crates/devup-mcp-figma/src/scripts/section_index.js @@ -32,13 +32,25 @@ let remainingPreviewBytes = 2048; // The menu needs enough copy to distinguish similarly named frames, without // returning their descendants or letting previews dominate the compact index. -function textPreview(root) { +// +// `allowance` is this candidate's share of the budget rather than the whole +// of what is left. Reading the pool directly spent it first-come: on the +// Braillify Studio login Section the first seven candidates took their full +// 120 characters — Korean is three UTF-8 bytes each, so 360 bytes apiece +// against a 2,048-byte pool — and the remaining seven came back +// `budget-exhausted` with nothing to read. That file names four frames +// `AUTH-01` and four `Frame 3`, so a candidate without text is a candidate +// that cannot be identified, and the previews that did land were three +// strings repeated twice over. Screens differ in their opening characters, +// so a short preview for every candidate is worth more than a long one for +// the first few. +function textPreview(root, allowance) { const queue = [root]; let preview = ""; let characters = 0; let bytes = 0; let scanTruncated = false; - if (remainingPreviewBytes === 0) return { text: "", state: "budget-exhausted" }; + if (allowance <= 0) return { text: "", state: "budget-exhausted", spent: 0 }; for (let index = 0; index < queue.length; index += 1) { const node = queue[index]; if (node.visible === false) continue; @@ -46,9 +58,12 @@ function textPreview(root) { const text = node.characters.replace(/\s+/g, " ").trim(); for (const character of (preview && text ? " " : "") + text) { const size = utf8ByteLength(character); - if (characters >= MAX_PREVIEW_CHARACTERS || bytes + size > remainingPreviewBytes) { - remainingPreviewBytes -= bytes; - return { text: preview.trimEnd(), state: size > remainingPreviewBytes ? "budget-exhausted" : "truncated" }; + if (characters >= MAX_PREVIEW_CHARACTERS || bytes + size > allowance) { + return { + text: preview.trimEnd(), + state: bytes + size > allowance ? "budget-exhausted" : "truncated", + spent: bytes, + }; } preview += character; characters += 1; @@ -61,8 +76,11 @@ function textPreview(root) { queue.push(...node.children.slice(0, room)); } } - remainingPreviewBytes -= bytes; - return { text: preview, state: scanTruncated ? "truncated" : (preview ? "available" : "no-text") }; + return { + text: preview, + state: scanTruncated ? "truncated" : (preview ? "available" : "no-text"), + spent: bytes, + }; } function bounds(node) { @@ -223,9 +241,17 @@ const sectionNode = { extra: {}, fieldErrors: {}, }; +let unfunded = selected.length; const candidates = selected.map(({ node, box }) => { const estimate = subtreeEstimate(node); - const preview = textPreview(node); + // An equal share of what is left, so the last candidate is funded before + // the first is indulged. What a candidate does not spend stays in the pool + // and widens every share after it, so a menu of short texts still reads in + // full. + const allowance = Math.floor(remainingPreviewBytes / unfunded); + unfunded -= 1; + const preview = textPreview(node, allowance); + remainingPreviewBytes -= preview.spent; return { id: node.id, type: node.type, diff --git a/crates/devup-mcp-figma/tests/explore_script_behavior.mjs b/crates/devup-mcp-figma/tests/explore_script_behavior.mjs index 3befcf0..5316e0e 100644 --- a/crates/devup-mcp-figma/tests/explore_script_behavior.mjs +++ b/crates/devup-mcp-figma/tests/explore_script_behavior.mjs @@ -121,10 +121,63 @@ test("Section preview text has per-candidate and aggregate limits", async () => pageWith(section); const result = await executeSection(section); const previews = result.nodes.slice(1).map(n => n.fields.textPreview); - assert.equal(Array.from(previews[0]).length, 120); + // Crowded, so the aggregate limit is the one that binds. It is shared out + // rather than taken first-come, so no candidate reaches the per-candidate + // ceiling here and, more to the point, none is left with nothing. assert.ok(previews.every(value => Array.from(value).length <= 120)); + assert.ok(previews.every(value => value.length > 0), JSON.stringify(previews)); assert.ok(previews.reduce((sum, value) => sum + Buffer.byteLength(value), 0) <= 2048); assert.ok(previews.every(value => value.isWellFormed())); + + // Uncrowded, so the per-candidate ceiling is the one that binds: a single + // candidate with the whole budget still stops at 120 characters. + const lone = sceneNode({ id: "copy-lone", type: "TEXT" }); + lone.characters = "안내😀".repeat(300); + const only = sceneNode({ id: "frame-lone", type: "FRAME", children: [lone] }); + const small = sceneNode({ id: "section-lone", type: "SECTION", children: [only] }); + pageWith(small); + const single = (await executeSection(small)).nodes[1].fields.textPreview; + assert.equal(Array.from(single).length, 120); +}); + +test("R21 the Section preview budget is shared between candidates, not taken", async () => { + // Braillify Studio's `로그인 화면`: fourteen screens, repeating names, Korean + // copy. Spent first-come, seven candidates took their full 120 characters — + // Korean is three UTF-8 bytes each, so 360 bytes apiece against a + // 2,048-byte pool — and the other seven came back empty. That file names + // four frames `AUTH-01` and four `Frame 3`, so a candidate with no text is + // one the caller cannot tell from its neighbours, which is the only thing + // a preview is for. + const frames = Array.from({ length: 14 }, (_, i) => { + const text = sceneNode({ id: `t${i}`, type: "TEXT" }); + text.characters = `${String(i + 1).padStart(2, "0")}번 화면 ${"읽을 수 있는 세상을 함께 만드는 점역 에디터 ".repeat(6)}`; + return sceneNode({ + id: `f${i}`, + type: "FRAME", + name: i % 2 === 0 ? "AUTH-01" : "AUTH-02", + children: [text], + }); + }); + const section = sceneNode({ id: "section", type: "SECTION", children: frames }); + pageWith(section); + const previews = (await executeSection(section)).nodes + .slice(1) + .map((node) => node.fields.textPreview); + + assert.equal(previews.length, 14); + assert.equal( + previews.filter((preview) => preview.length === 0).length, + 0, + `candidates left unidentifiable: ${JSON.stringify(previews)}`, + ); + // Enough of each to carry the part that differs, and all different. + assert.ok( + Math.min(...previews.map((preview) => Array.from(preview).length)) >= 8, + JSON.stringify(previews), + ); + assert.equal(new Set(previews).size, previews.length); + // Sharing the pool must not enlarge it. + assert.ok(previews.reduce((sum, value) => sum + Buffer.byteLength(value), 0) <= 2048); }); function sceneNode({ diff --git a/crates/devup-mcp/src/lib.rs b/crates/devup-mcp/src/lib.rs index 628032c..954b2e6 100644 --- a/crates/devup-mcp/src/lib.rs +++ b/crates/devup-mcp/src/lib.rs @@ -1,5 +1,6 @@ pub mod asset_batches; pub mod server; +pub mod skills; #[cfg(test)] #[path = "../tests/support/paths.rs"] @@ -26,6 +27,11 @@ pub struct ServerConfig { pub figma_client_name: Option, } +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SkillCommandConfig { + pub skill_dirs: Vec, +} + /// Fully resolved Figma direct-connection configuration: cli-arg values /// (if any) win over environment variables, which win over "nothing /// configured here" (the persisted `configure` store, if any, is resolved @@ -109,6 +115,8 @@ pub enum CliAction { Version, SelfCheck, MergeAssetBatches(Vec), + InstallSkills(SkillCommandConfig), + CheckSkills(SkillCommandConfig), Serve(ServerConfig), } @@ -138,12 +146,16 @@ where let mut figma_client_secret: Option = None; let mut figma_callback_port: Option = None; let mut figma_client_name: Option = None; + let mut skill_dirs = Vec::new(); + let mut skill_action: Option = None; while let Some(argument) = arguments.next() { let no_other_options_yet = roots.is_empty() && figma_client_id.is_none() && figma_client_secret.is_none() && figma_callback_port.is_none() - && figma_client_name.is_none(); + && figma_client_name.is_none() + && skill_dirs.is_empty() + && skill_action.is_none(); match argument.to_str() { Some("--version" | "-V") if no_other_options_yet && arguments.peek().is_none() => { return Ok(CliAction::Version); @@ -159,7 +171,54 @@ where ); return Ok(CliAction::MergeAssetBatches(paths)); } + Some("--install-skills") => { + anyhow::ensure!( + roots.is_empty() + && figma_client_id.is_none() + && figma_client_secret.is_none() + && figma_callback_port.is_none() + && figma_client_name.is_none() + && skill_action.is_none(), + "--install-skills cannot be combined with server options or --check-skills." + ); + skill_action = Some(true); + } + Some("--check-skills") => { + anyhow::ensure!( + roots.is_empty() + && figma_client_id.is_none() + && figma_client_secret.is_none() + && figma_callback_port.is_none() + && figma_client_name.is_none() + && skill_action.is_none(), + "--check-skills cannot be combined with server options or --install-skills." + ); + skill_action = Some(false); + } + Some("--skill-dir") => { + anyhow::ensure!( + roots.is_empty() + && figma_client_id.is_none() + && figma_client_secret.is_none() + && figma_callback_port.is_none() + && figma_client_name.is_none(), + "--skill-dir cannot be combined with server options." + ); + let directory = arguments.next().ok_or_else(|| { + anyhow::anyhow!("--skill-dir requires an existing directory path.") + })?; + let directory = PathBuf::from(directory); + anyhow::ensure!( + directory.is_dir(), + "--skill-dir must be an existing directory." + ); + skill_dirs.push(directory); + } Some("--allow-write-root") => { + anyhow::ensure!( + skill_action.is_none() && skill_dirs.is_empty(), + "--allow-write-root cannot be combined with skill commands." + ); let root = arguments.next().ok_or_else(|| { anyhow::anyhow!("--allow-write-root requires a directory path.") })?; @@ -170,6 +229,10 @@ where roots.push(root); } Some("--figma-client-id") => { + anyhow::ensure!( + skill_action.is_none() && skill_dirs.is_empty(), + "--figma-client-id cannot be combined with skill commands." + ); let value = arguments .next() .ok_or_else(|| anyhow::anyhow!("--figma-client-id requires a value."))?; @@ -183,6 +246,10 @@ where figma_client_id = Some(value); } Some("--figma-client-secret") => { + anyhow::ensure!( + skill_action.is_none() && skill_dirs.is_empty(), + "--figma-client-secret cannot be combined with skill commands." + ); let value = arguments .next() .ok_or_else(|| anyhow::anyhow!("--figma-client-secret requires a value."))?; @@ -198,6 +265,10 @@ where figma_client_secret = Some(value); } Some("--figma-client-name") => { + anyhow::ensure!( + skill_action.is_none() && skill_dirs.is_empty(), + "--figma-client-name cannot be combined with skill commands." + ); let value = arguments .next() .ok_or_else(|| anyhow::anyhow!("--figma-client-name requires a value."))?; @@ -212,6 +283,10 @@ where figma_client_name = Some(value); } Some("--figma-callback-port") => { + anyhow::ensure!( + skill_action.is_none() && skill_dirs.is_empty(), + "--figma-callback-port cannot be combined with skill commands." + ); let value = arguments.next().ok_or_else(|| { anyhow::anyhow!("--figma-callback-port requires a port number.") })?; @@ -226,6 +301,18 @@ where None => anyhow::bail!("devup-mcp arguments must be UTF-8 flags."), } } + if let Some(install) = skill_action { + let config = SkillCommandConfig { skill_dirs }; + return Ok(if install { + CliAction::InstallSkills(config) + } else { + CliAction::CheckSkills(config) + }); + } + anyhow::ensure!( + skill_dirs.is_empty(), + "--skill-dir requires --install-skills or --check-skills." + ); if roots.is_empty() { roots.push(std::env::current_dir()?); } diff --git a/crates/devup-mcp/src/main.rs b/crates/devup-mcp/src/main.rs index b72fb95..65ba151 100644 --- a/crates/devup-mcp/src/main.rs +++ b/crates/devup-mcp/src/main.rs @@ -20,6 +20,20 @@ async fn main() -> anyhow::Result<()> { ); return Ok(()); } + if let devup_mcp::CliAction::InstallSkills(config) = &action { + println!( + "{}", + serde_json::to_string_pretty(&devup_mcp::skills::install(config).await?)? + ); + return Ok(()); + } + if let devup_mcp::CliAction::CheckSkills(config) = &action { + println!( + "{}", + serde_json::to_string_pretty(&devup_mcp::skills::check(config).await?)? + ); + return Ok(()); + } let devup_mcp::CliAction::Serve(config) = action else { unreachable!("version action returned above") }; diff --git a/crates/devup-mcp/src/server/mod.rs b/crates/devup-mcp/src/server/mod.rs index 9f3c5af..fb00cd4 100644 --- a/crates/devup-mcp/src/server/mod.rs +++ b/crates/devup-mcp/src/server/mod.rs @@ -1105,10 +1105,20 @@ impl DevupServer { ))); } } + // A collection of any size answers `in_progress` first, so this + // poll — not the call that started it — is what hands the caller + // their TSX. Checking it only on the synchronous returns left + // every real export unchecked. + let project_root = input.project_root.clone(); return job .wait_briefly() .await - .map(tool_result) + .map(|result| { + tool_result(with_project_theme_validation( + result, + project_root.as_deref(), + )) + }) .map_err(to_mcp_error); } if workflow.job_action.is_some() { @@ -1258,6 +1268,56 @@ impl DevupServer { false, ))); } + // A Section index already knows every candidate's name and + // width, which is all a breakpoint family is decided on. Ask + // here, where the answer costs nothing: the same refusal from + // projection arrives only after the whole collection has run. + if !input.frame_ids.is_empty() + && input.outputs.iter().any(|output| output == "responsiveTsx") + { + let selected = input + .frame_ids + .iter() + .filter_map(|id| { + index + .candidates + .iter() + .find(|candidate| candidate.node_id == *id) + }) + .map(|candidate| (candidate.name.as_str(), candidate.bounds.width)) + .collect::>(); + // Only when every selected frame was found in the index. + // A frame the index does not describe leaves the question + // open, and an open question is collected, not refused. + if selected.len() == input.frame_ids.len() + && !devup_mcp_devup_ui::codegen::responsive::breakpoint_family_is_possible( + &selected, + ) + { + let mut arguments = json!(input); + arguments["outputs"] = json!(["tsx"]); + arguments["frameIds"] = json!([input.frame_ids[0]]); + return Err(to_mcp_error(DevupError::with_details( + ErrorCode::DevupInvalidInput, + "responsiveTsx needs the selected frames to be one screen drawn at several widths, and these are not. Nothing was collected.", + false, + json!({ + "output": "responsiveTsx", + "selectedFrames": selected + .iter() + .map(|(name, width)| json!({"name": name, "width": width})) + .collect::>(), + "recoveryState": "available", + "nextAction": { + "tool": "devup_figma_export", + "arguments": arguments, + "why": "Each selected frame still converts on its own.", + "how": "Request tsx one frame at a time, repeating for each frameId you selected.", + }, + }), + ))); + } + } let mut request = CollectionRequest::new(artifact.payload.target.clone(), collection_scope); request.resource_scope = ResourceScope::Used; @@ -1293,7 +1353,10 @@ impl DevupServer { ) .await .map_err(to_mcp_error)?; - return Ok(tool_result(result)); + return Ok(tool_result(with_project_theme_validation( + result, + input.project_root.as_deref(), + ))); } validate_artifact_projection( &artifact, @@ -1329,7 +1392,10 @@ impl DevupServer { ) .await .map_err(to_mcp_error)?; - return Ok(tool_result(result)); + return Ok(tool_result(with_project_theme_validation( + result, + input.project_root.as_deref(), + ))); } let url = input.url.as_deref().ok_or_else(|| { @@ -1392,7 +1458,10 @@ impl DevupServer { ) .await .map_err(to_mcp_error)?; - Ok(tool_result(result)) + Ok(tool_result(with_project_theme_validation( + result, + input.project_root.as_deref(), + ))) } #[tool( @@ -1563,6 +1632,130 @@ fn section_index_from_payload(payload: &CollectedPayload) -> Option) -> Value { + let Some(project_root) = project_root else { + return result; + }; + const OUTPUTS: [&str; 3] = ["tsx", "componentTsx", "responsiveTsx"]; + let mut generated: Vec<(String, String)> = OUTPUTS + .into_iter() + .filter_map(|key| { + result + .get(key) + .and_then(Value::as_str) + .map(|tsx| (key.to_owned(), tsx.to_owned())) + }) + .collect(); + // A Section export answers under `frames`, one entry per selected frame, + // and nothing at the top level. Reading only the top level checked the + // single-node `url` case and silently skipped every `frameIds` call — + // which is every Section workflow, and so every screen of the Braillify + // Studio handover this exists for. + if let Some(frames) = result.get("frames").and_then(Value::as_array) { + for frame in frames { + let node = frame + .get("nodeId") + .and_then(Value::as_str) + .unwrap_or("frame") + .to_owned(); + for key in OUTPUTS { + if let Some(tsx) = frame.get(key).and_then(Value::as_str) { + generated.push((format!("{node}:{key}"), tsx.to_owned())); + } + } + } + } + if generated.is_empty() { + // Resource delivery hands the code back as a link, so there is no + // source here to check. Saying so is the point: an absent verdict + // reads exactly like a clean one, and this export is neither. + if result.get("resources").is_some_and(|r| !r.is_null()) { + result["projectThemeValidation"] = json!({ + "state": "not-checked", + "reason": "The outputs were delivered as resources, so no source was present to check.", + "note": "Request delivery=inline to have the generated tokens checked against this project.", + }); + } + return result; + } + let lookup = match project_context::theme_for_validation(Some(project_root)) { + Ok(lookup) => lookup, + Err(error) => { + result["projectThemeValidation"] = json!({ + "state": "unavailable", + "reason": error.message, + "note": "The generated tokens could not be checked against this project.", + }); + return result; + } + }; + let mut outputs = serde_json::Map::new(); + for (key, tsx) in generated { + let report = devup_mcp_devup_ui::ui_validate::validate_devup_ui_tsx( + &tsx, + lookup.theme.as_ref(), + false, + ); + // Only the findings a caller has to act on. The hardcoded-value + // information is already in `fidelity`, and repeating twenty of them + // here would bury the handful that stop the code compiling into a + // theme. + let unknown = report + .violations + .iter() + .filter(|violation| violation.rule == "unknown-token") + .map(|violation| { + json!({ + "message": violation.message, + "suggestion": violation.suggestion, + }) + }) + .collect::>(); + outputs.insert( + key.to_owned(), + json!({ + "ok": report.ok, + "unknownTokenCount": unknown.len(), + "unknownTokens": unknown, + }), + ); + } + let any_unknown = outputs + .values() + .any(|output| output["unknownTokenCount"].as_u64().unwrap_or(0) > 0); + result["projectThemeValidation"] = json!({ + "state": if lookup.theme.is_some() { "checked" } else { "no-theme" }, + "themeAvailable": lookup.theme.is_some(), + "guardrail": lookup.guardrail, + "outputs": outputs, + "note": if any_unknown { + "The generated tokens are the Figma names. This project defines different ones; map each unknown token to the project's own before using this TSX, or add the missing tokens to devup.json." + } else { + "Every token the generated TSX references exists in this project's devup.json." + }, + }); + result +} + fn section_candidate_as_explore(candidate: &SectionCandidate) -> ExploreCandidate { ExploreCandidate { node: ExploreNode { diff --git a/crates/devup-mcp/src/server/project_context.rs b/crates/devup-mcp/src/server/project_context.rs index dc19940..10a00f5 100644 --- a/crates/devup-mcp/src/server/project_context.rs +++ b/crates/devup-mcp/src/server/project_context.rs @@ -187,10 +187,13 @@ pub async fn run( })?, }; let Some(root) = find_project_root(&start) else { - return Ok(not_found_response( - PROJECT_ROOT_NOT_FOUND_MESSAGE, - vec![display_path(&start)], - )); + let response = + not_found_response(PROJECT_ROOT_NOT_FOUND_MESSAGE, vec![display_path(&start)]); + return Ok(if matches!(scope, "theme" | "all") { + attach_theme_semantics(response) + } else { + response + }); }; match scope { @@ -220,11 +223,11 @@ fn theme_scope(root: &Path, filter: Option<&str>) -> Value { files.sort(); files.dedup(); if files.is_empty() { - return not_found_with_exclusions( + return attach_theme_semantics(not_found_with_exclusions( "No devup.json found. Do not write code by guessing color, typography, length, or shadow token names.", vec![display_path(&root.join("devup.json"))], excluded, - ); + )); } let mut projects = Vec::new(); for file in &files { @@ -331,6 +334,32 @@ fn theme_scope(root: &Path, filter: Option<&str>) -> Value { "files": projects, }); attach_scan_notes(&mut response, excluded, files.len(), "devup.json"); + attach_theme_semantics(response) +} + +fn attach_theme_semantics(mut response: Value) -> Value { + let Some(object) = response.as_object_mut() else { + return response; + }; + object.insert( + "modeResolution".to_owned(), + json!({ + "order": "active mode -> selected default mode", + "defaultModeSelection": ["default", "light", "first mode in lexical order"], + "note": "A token absent from a mode resolves through this chain. Equal values across modes are a design choice, not a defect." + }), + ); + object.insert( + "responsiveArrayOrder".to_owned(), + json!(["mobile", "sm", "tablet", "lg", "PC"]), + ); + object.insert( + "propConventions".to_owned(), + json!({ + "colorAndLength": "$token", + "typography": "bare token name, no $ prefix" + }), + ); response } @@ -682,6 +711,23 @@ mod tests { result["files"][0]["colors"]["default"]["captionLight"], "#999999" ); + assert_eq!( + result["modeResolution"]["order"], + "active mode -> selected default mode" + ); + assert_eq!( + result["modeResolution"]["defaultModeSelection"], + json!(["default", "light", "first mode in lexical order"]) + ); + assert_eq!( + result["responsiveArrayOrder"], + json!(["mobile", "sm", "tablet", "lg", "PC"]) + ); + assert_eq!(result["propConventions"]["colorAndLength"], "$token"); + assert_eq!( + result["propConventions"]["typography"], + "bare token name, no $ prefix" + ); } #[tokio::test] @@ -693,6 +739,7 @@ mod tests { .unwrap(); assert_eq!(result["found"], false); assert_eq!(result["guardrail"]["action"], "stop-and-report"); + assert!(result.get("modeResolution").is_some()); } #[tokio::test] diff --git a/crates/devup-mcp/src/server/tools.rs b/crates/devup-mcp/src/server/tools.rs index 971840b..5cb5fe4 100644 --- a/crates/devup-mcp/src/server/tools.rs +++ b/crates/devup-mcp/src/server/tools.rs @@ -96,6 +96,30 @@ pub struct FigmaExportInput { #[serde(default = "default_delivery")] #[schemars(extend("enum" = super::validation::DELIVERY_MODES))] pub delivery: String, + /// The project the generated TSX is going into, so the export can say + /// whether it fits. + /// + /// Tokens are named after the Figma variables and text styles a screen + /// actually uses. That is right for a project with no `devup.json` yet, + /// and wrong for one that already has its own names: a Braillify Studio + /// login screen came back asking for `$background`, `$innerBg`, + /// `$kakaoLogo`, `$title`, `$textSub`, `$borderLight` and the typography + /// `mainSubText`, `titleSmMed`, `bodyMed`, of which that project defines + /// none — it calls them `$bg`, `$panel`, `$text`, `$textSubtle`, + /// `$borderStrong`, `body`, `bodyL`. Every one of those is an error + /// `devup_ui_validate` reports against the same project, so the export + /// handed back code this server's own validator refuses. + /// + /// Given a root, `projectThemeValidation` carries that verdict in the + /// export itself, naming the tokens that do not exist and what the + /// project calls the ones it has. Omitted, nothing is read from disk and + /// the response is unchanged. + /// + /// Pass it on whichever call returns the outputs. A collection of any + /// size answers `in_progress` first and hands the TSX back from the + /// `jobId` poll, so that poll needs the root too. + #[serde(default)] + pub project_root: Option, } #[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] diff --git a/crates/devup-mcp/src/skills/mod.rs b/crates/devup-mcp/src/skills/mod.rs new file mode 100644 index 0000000..2ced9f6 --- /dev/null +++ b/crates/devup-mcp/src/skills/mod.rs @@ -0,0 +1,225 @@ +use std::{ + path::{Path, PathBuf}, + time::{SystemTime, UNIX_EPOCH}, +}; + +use anyhow::Context; +use serde::{Deserialize, Serialize}; +use sha2::{Digest, Sha256}; + +use crate::{ + SkillCommandConfig, + server::output::{OutputPolicy, OutputTransaction}, +}; + +mod upstream; + +pub use upstream::{ + FetchedSkill, RawGithubSkillUpstream, SKILL_SOURCE_URL, SkillFetchError, SkillUpstream, +}; + +const SKILL_NAME: &str = "devup-ui"; +const PROVENANCE_FILE: &str = "SKILL.md.provenance.json"; + +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SkillReport { + pub operation: &'static str, + pub source_url: &'static str, + pub targets: Vec, +} + +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TargetReport { + pub path: String, + pub status: &'static str, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +struct SkillProvenance { + source_url: String, + etag: String, + fetched_at: u64, + sha256: String, +} + +pub async fn install(config: &SkillCommandConfig) -> anyhow::Result { + let (targets, mut skipped) = resolve_targets(&config.skill_dirs)?; + if targets.is_empty() { + let paths = skipped + .iter() + .map(|target| target.path.as_str()) + .collect::>() + .join(", "); + anyhow::bail!( + "No skill directory was detected. Skipped {paths} because their parent skill directories do not exist. Create one, or pass an existing directory with --skill-dir." + ); + } + let upstream = RawGithubSkillUpstream::new()?; + let fetched = upstream.fetch().await?; + if config.skill_dirs.is_empty() { + for target in &targets { + if !target.is_dir() { + std::fs::create_dir(target).with_context(|| { + format!( + "Cannot create detected skill directory {}.", + target.display() + ) + })?; + } + } + } + let fetched_at = SystemTime::now() + .duration_since(UNIX_EPOCH) + .context("The system clock is before the Unix epoch.")? + .as_secs(); + let mut report = install_fetched(fetched, &targets, fetched_at)?; + report.targets.append(&mut skipped); + Ok(report) +} + +pub async fn check(config: &SkillCommandConfig) -> anyhow::Result { + let (targets, mut skipped) = resolve_targets(&config.skill_dirs)?; + let mut report = check_with(&RawGithubSkillUpstream::new()?, &targets).await?; + report.targets.append(&mut skipped); + Ok(report) +} + +pub async fn install_with( + upstream: &dyn SkillUpstream, + targets: &[PathBuf], + fetched_at: u64, +) -> anyhow::Result { + let fetched = upstream.fetch().await?; + install_fetched(fetched, targets, fetched_at) +} + +fn install_fetched( + fetched: FetchedSkill, + targets: &[PathBuf], + fetched_at: u64, +) -> anyhow::Result { + let provenance = SkillProvenance { + source_url: SKILL_SOURCE_URL.to_owned(), + etag: fetched.etag, + fetched_at, + sha256: sha256(&fetched.contents), + }; + let mut provenance_bytes = serde_json::to_vec_pretty(&provenance)?; + provenance_bytes.push(b'\n'); + let mut reports = Vec::with_capacity(targets.len()); + for target in targets { + let policy = OutputPolicy::from_roots(vec![target.clone()]).map_err(|error| { + anyhow::anyhow!( + "Cannot install devup-ui skill into {}: {}", + target.display(), + error.message + ) + })?; + let mut transaction = OutputTransaction::new(); + transaction + .stage("skill", policy.resolve("SKILL.md")?, &fetched.contents) + .and_then(|()| { + transaction.stage( + "provenance", + policy.resolve(PROVENANCE_FILE)?, + &provenance_bytes, + ) + }) + .and_then(|()| transaction.commit().map(|_| ())) + .map_err(|error| { + anyhow::anyhow!( + "Cannot install devup-ui skill into {}: {}. Ensure the directory is writable and retry.", + target.display(), + error.message + ) + })?; + reports.push(target_report(target, "installed")); + } + Ok(SkillReport { + operation: "install", + source_url: SKILL_SOURCE_URL, + targets: reports, + }) +} + +pub async fn check_with( + upstream: &dyn SkillUpstream, + targets: &[PathBuf], +) -> anyhow::Result { + let fetched = upstream.fetch().await?; + let upstream_hash = sha256(&fetched.contents); + let targets = targets + .iter() + .map(|target| { + let status = installed_status(target, &fetched.etag, &upstream_hash); + target_report(target, status) + }) + .collect(); + Ok(SkillReport { + operation: "check", + source_url: SKILL_SOURCE_URL, + targets, + }) +} + +fn installed_status(target: &Path, etag: &str, upstream_hash: &str) -> &'static str { + let skill_path = target.join("SKILL.md"); + let Ok(contents) = std::fs::read(&skill_path) else { + return "not-installed"; + }; + let provenance = std::fs::read(target.join(PROVENANCE_FILE)) + .ok() + .and_then(|bytes| serde_json::from_slice::(&bytes).ok()); + provenance.map_or("stale", |provenance| { + if provenance.source_url == SKILL_SOURCE_URL + && provenance.etag == etag + && provenance.sha256 == upstream_hash + && sha256(&contents) == upstream_hash + { + "up-to-date" + } else { + "stale" + } + }) +} + +fn resolve_targets(explicit: &[PathBuf]) -> anyhow::Result<(Vec, Vec)> { + if !explicit.is_empty() { + return Ok((explicit.to_vec(), Vec::new())); + } + let home = std::env::var_os(if cfg!(windows) { "USERPROFILE" } else { "HOME" }) + .map(PathBuf::from) + .context("Could not determine the home directory. Pass --skill-dir explicitly.")?; + let roots = [ + home.join(".config/opencode/skill"), + home.join(".claude/skills"), + ]; + let mut targets = Vec::new(); + let mut skipped = Vec::new(); + for root in roots { + if root.is_dir() { + let target = root.join(SKILL_NAME); + targets.push(target); + } else { + skipped.push(target_report(&root.join(SKILL_NAME), "skipped")); + } + } + Ok((targets, skipped)) +} + +fn target_report(path: &Path, status: &'static str) -> TargetReport { + TargetReport { + path: path.to_string_lossy().into_owned(), + status, + } +} + +fn sha256(contents: &[u8]) -> String { + Sha256::digest(contents) + .iter() + .map(|byte| format!("{byte:02x}")) + .collect() +} diff --git a/crates/devup-mcp/src/skills/upstream.rs b/crates/devup-mcp/src/skills/upstream.rs new file mode 100644 index 0000000..1df4080 --- /dev/null +++ b/crates/devup-mcp/src/skills/upstream.rs @@ -0,0 +1,102 @@ +use std::{ + fmt::{Display, Formatter}, + time::Duration, +}; + +use anyhow::Context; +use async_trait::async_trait; +use reqwest::header::ETAG; + +pub const SKILL_SOURCE_URL: &str = + "https://raw.githubusercontent.com/dev-five-git/devup-ui/refs/heads/main/SKILL.md"; + +#[derive(Debug, Clone)] +pub struct FetchedSkill { + pub contents: Vec, + pub etag: String, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum SkillFetchError { + Network(String), + NotFound, + HttpStatus(u16), + MissingEtag, +} + +impl Display for SkillFetchError { + fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Self::Network(message) => write!( + formatter, + "network failure while fetching {SKILL_SOURCE_URL}: {message}. Check connectivity and retry." + ), + Self::NotFound => write!( + formatter, + "GitHub returned 404 for {SKILL_SOURCE_URL}. Verify that the public main-branch SKILL.md still exists." + ), + Self::HttpStatus(status) => write!( + formatter, + "GitHub returned HTTP {status} for {SKILL_SOURCE_URL}. Retry later or verify GitHub availability." + ), + Self::MissingEtag => write!( + formatter, + "GitHub returned {SKILL_SOURCE_URL} without an ETag, so its provenance cannot be verified." + ), + } + } +} + +impl std::error::Error for SkillFetchError {} + +#[async_trait] +pub trait SkillUpstream: Send + Sync { + async fn fetch(&self) -> Result; +} + +pub struct RawGithubSkillUpstream { + client: reqwest::Client, +} + +impl RawGithubSkillUpstream { + pub fn new() -> anyhow::Result { + let client = reqwest::Client::builder() + .timeout(Duration::from_secs(30)) + .user_agent(concat!("devup-mcp/", env!("CARGO_PKG_VERSION"))) + .build() + .context("Could not create the HTTPS client for skill delivery.")?; + Ok(Self { client }) + } +} + +#[async_trait] +impl SkillUpstream for RawGithubSkillUpstream { + async fn fetch(&self) -> Result { + let response = self + .client + .get(SKILL_SOURCE_URL) + .send() + .await + .map_err(|error| SkillFetchError::Network(error.to_string()))?; + let status = response.status(); + if status == reqwest::StatusCode::NOT_FOUND { + return Err(SkillFetchError::NotFound); + } + if !status.is_success() { + return Err(SkillFetchError::HttpStatus(status.as_u16())); + } + let etag = response + .headers() + .get(ETAG) + .and_then(|value| value.to_str().ok()) + .filter(|value| !value.is_empty()) + .ok_or(SkillFetchError::MissingEtag)? + .to_owned(); + let contents = response + .bytes() + .await + .map_err(|error| SkillFetchError::Network(error.to_string()))? + .to_vec(); + Ok(FetchedSkill { contents, etag }) + } +} diff --git a/crates/devup-mcp/tests/cli.rs b/crates/devup-mcp/tests/cli.rs index ef9c968..d86086d 100644 --- a/crates/devup-mcp/tests/cli.rs +++ b/crates/devup-mcp/tests/cli.rs @@ -187,6 +187,51 @@ fn invalid_cli_arguments_fail_without_starting_stdio() -> anyhow::Result<()> { Ok(()) } +#[test] +fn skill_commands_accept_repeated_explicit_dirs_and_reject_mixed_modes() -> anyhow::Result<()> { + let first = std::env::temp_dir().join(format!( + "devup-mcp-skill-cli-first-{}", + rand::random::() + )); + let second = std::env::temp_dir().join(format!( + "devup-mcp-skill-cli-second-{}", + rand::random::() + )); + fs::create_dir_all(&first)?; + fs::create_dir_all(&second)?; + + let action = parse_cli_args([ + OsString::from("--install-skills"), + OsString::from("--skill-dir"), + first.clone().into_os_string(), + OsString::from("--skill-dir"), + second.clone().into_os_string(), + ])?; + let CliAction::InstallSkills(config) = action else { + panic!("--install-skills must select the installer") + }; + assert_eq!(config.skill_dirs, vec![first.clone(), second.clone()]); + assert!( + parse_cli_args([ + OsString::from("--install-skills"), + OsString::from("--check-skills") + ]) + .is_err() + ); + assert!( + parse_cli_args([ + OsString::from("--install-skills"), + OsString::from("--allow-write-root"), + first.clone().into_os_string(), + ]) + .is_err() + ); + + fs::remove_dir_all(first)?; + fs::remove_dir_all(second)?; + Ok(()) +} + #[test] fn no_arguments_use_the_startup_current_directory() -> anyhow::Result<()> { let action = parse_cli_args(std::iter::empty::())?; diff --git a/crates/devup-mcp/tests/export_project_theme.rs b/crates/devup-mcp/tests/export_project_theme.rs new file mode 100644 index 0000000..e2c8e97 --- /dev/null +++ b/crates/devup-mcp/tests/export_project_theme.rs @@ -0,0 +1,223 @@ +//! Whether the generated TSX fits the project it is going into. +//! +//! Tokens are named after the Figma variables a screen uses. For a project +//! with no `devup.json` that is the right answer. For one that already has +//! its own names it is not, and the export had no way to know them: a +//! Braillify Studio login screen came back referencing nine tokens that +//! project does not define, `devup_ui_validate` refused the very same code +//! against the very same root, and the export said nothing about it. + +use std::{fs, path::PathBuf, sync::Arc}; + +use async_trait::async_trait; +use devup_mcp::server::{DevupAuth, DevupServer, Services}; +use devup_mcp_figma::{AuthStatus, DevupError, FigmaUpstream, ReadToolCall, UpstreamResult}; +use rmcp::{ServiceExt, model::CallToolRequestParams}; +use serde_json::{Map, Value, json}; + +#[derive(Debug)] +struct ConnectedAuth; + +#[async_trait] +impl DevupAuth for ConnectedAuth { + async fn status(&self) -> Result { + Ok(AuthStatus::Connected) + } + async fn login(&self) -> Result { + Ok(AuthStatus::Connected) + } + async fn logout(&self) -> Result { + Ok(AuthStatus::Disconnected) + } +} + +/// One frame filled with a variable the Figma file calls `primary`. +#[derive(Debug)] +struct PrimaryFillUpstream; + +#[async_trait] +impl FigmaUpstream for PrimaryFillUpstream { + async fn list_tools(&self) -> Result, DevupError> { + Ok(vec!["use_figma".to_owned()]) + } + async fn call_read_tool(&self, call: ReadToolCall) -> Result { + let payload = match call { + ReadToolCall::Metadata { .. } => json!({"devupMetadata": { + "fileKey": "85CgSws3o5XsLv7aAwWJyS", "version": "1", "rootId": "3879:35481", + "nodes": [{"id": "3879:35481", "type": "FRAME", "childrenIds": [], "descendantCount": 1}] + }}), + ReadToolCall::Snapshot { + script: devup_mcp_figma::BuiltinScript::NodeSnapshot, + .. + } => json!({ + "fileKey": "85CgSws3o5XsLv7aAwWJyS", "version": "1", "rootIds": ["3879:35481"], + "nodes": [{ + "id": "3879:35481", "type": "FRAME", + "fields": { + "name": "Proofread", "childrenIds": [], "layoutMode": "VERTICAL", + "width": 320, "height": 240, + "fills": [{ + "type": "SOLID", "color": {"r": 0, "g": 0.4, "b": 1, "a": 1}, + "boundVariables": {"color": {"type": "VARIABLE_ALIAS", "id": "v"}} + }], + "boundVariables": {"fills": [{"type": "VARIABLE_ALIAS", "id": "v"}]} + }, + "extra": {}, "fieldErrors": {} + }], "diagnostics": [] + }), + ReadToolCall::Snapshot { + script: devup_mcp_figma::BuiltinScript::VariableCatalog, + .. + } => json!({ + "collections": [{"id": "c", "name": "Theme", "defaultModeId": "m", + "modes": [{"modeId": "m", "name": "Default"}]}], + "variableIds": ["v"], "styles": [], + "localComplete": true, "usedRemoteComplete": true + }), + ReadToolCall::Snapshot { + script: devup_mcp_figma::BuiltinScript::LocalVariables, + .. + } => json!({"variables": [{ + "id": "v", "name": "Color/Primary", "resolvedType": "COLOR", + "variableCollectionId": "c", "codeSyntax": {"WEB": "primary"}, + "valuesByMode": {"m": {"r": 0, "g": 0.4, "b": 1, "a": 1}} + }], "styles": []}), + ReadToolCall::Snapshot { + script: devup_mcp_figma::BuiltinScript::UsedResources, + .. + } => json!({ + "collections": [{"id": "c", "name": "Theme", "defaultModeId": "m", + "modes": [{"modeId": "m", "name": "Default"}]}], + "variables": [{ + "id": "v", "name": "Color/Primary", "resolvedType": "COLOR", + "variableCollectionId": "c", "codeSyntax": {"WEB": "primary"}, + "valuesByMode": {"m": {"r": 0, "g": 0.4, "b": 1, "a": 1}} + }], + "styles": [], "unresolved": [] + }), + _ => { + return Err(DevupError::new( + devup_mcp_figma::ErrorCode::DevupSnapshotUnsupported, + "unexpected test call", + false, + )); + } + }; + Ok(UpstreamResult { + raw: json!({"structuredContent": {"result": payload}}), + }) + } +} + +async fn export(arguments: Value) -> anyhow::Result { + let server = DevupServer::new(Services::new( + Arc::new(ConnectedAuth), + Arc::new(PrimaryFillUpstream), + )); + let (server_transport, client_transport) = tokio::io::duplex(256 * 1024); + let task = tokio::spawn(async move { + server.serve(server_transport).await?.waiting().await?; + anyhow::Ok(()) + }); + let client = ().serve(client_transport).await?; + let arguments: Map = arguments.as_object().cloned().unwrap(); + let result = client + .call_tool(CallToolRequestParams::new("devup_figma_export").with_arguments(arguments)) + .await?; + let structured = result.structured_content.clone(); + client.cancel().await?; + task.await??; + anyhow::ensure!(result.is_error != Some(true), "{structured:?}"); + Ok(structured.expect("structured output")) +} + +/// A project whose `devup.json` names this colour something else entirely. +fn project_naming_it_brand() -> anyhow::Result { + let root = std::env::temp_dir().join(format!("devup-f3-{}", std::process::id())); + fs::create_dir_all(&root)?; + fs::write(root.join("package.json"), r#"{"name":"fixture"}"#)?; + fs::write( + root.join("devup.json"), + r##"{"theme":{"colors":{"default":{"brand":"#0066FF"}},"typography":{},"length":{},"shadow":{}}}"##, + )?; + Ok(root) +} + +const URL: &str = "https://www.figma.com/design/85CgSws3o5XsLv7aAwWJyS/Fixture?node-id=3879-35481"; + +#[tokio::test] +async fn an_export_without_a_project_root_reads_nothing_from_disk() -> anyhow::Result<()> { + let result = export(json!({"url": URL, "outputs": ["tsx"]})).await?; + assert!( + result["tsx"] + .as_str() + .unwrap_or_default() + .contains("$primary"), + "the fixture must generate the Figma name: {}", + result["tsx"] + ); + assert!( + result.get("projectThemeValidation").is_none(), + "no root was given, so nothing may be claimed about any project" + ); + Ok(()) +} + +/// The defect, stated as the caller experiences it: the export hands back +/// TSX this server's own validator refuses against the project it is for, +/// and only a separate `devup_ui_validate` call revealed it. +#[tokio::test] +async fn an_export_names_the_tokens_the_project_does_not_define() -> anyhow::Result<()> { + let root = project_naming_it_brand()?; + let result = export(json!({ + "url": URL, + "outputs": ["tsx"], + "projectRoot": root.to_string_lossy(), + })) + .await?; + + let verdict = &result["projectThemeValidation"]; + assert_eq!(verdict["state"], "checked", "{result}"); + assert_eq!(verdict["themeAvailable"], true); + let tsx = &verdict["outputs"]["tsx"]; + assert_eq!(tsx["ok"], false, "$primary is not in this project: {tsx}"); + assert_eq!(tsx["unknownTokenCount"], 1, "{tsx}"); + assert!( + tsx["unknownTokens"][0]["message"] + .as_str() + .unwrap_or_default() + .contains("primary"), + "the verdict names the token: {tsx}" + ); + assert!( + verdict["note"] + .as_str() + .unwrap_or_default() + .contains("map each unknown token"), + "{verdict}" + ); + Ok(()) +} + +/// A project that does define the name is told so, rather than left to infer +/// it from an absent warning. +#[tokio::test] +async fn an_export_confirms_a_project_that_already_has_the_token() -> anyhow::Result<()> { + let root = std::env::temp_dir().join(format!("devup-f3-ok-{}", std::process::id())); + fs::create_dir_all(&root)?; + fs::write(root.join("package.json"), r#"{"name":"fixture"}"#)?; + fs::write( + root.join("devup.json"), + r##"{"theme":{"colors":{"default":{"primary":"#0066FF"}},"typography":{},"length":{},"shadow":{}}}"##, + )?; + let result = export(json!({ + "url": URL, + "outputs": ["tsx"], + "projectRoot": root.to_string_lossy(), + })) + .await?; + let tsx = &result["projectThemeValidation"]["outputs"]["tsx"]; + assert_eq!(tsx["unknownTokenCount"], 0, "{tsx}"); + assert_eq!(tsx["ok"], true, "{tsx}"); + Ok(()) +} diff --git a/crates/devup-mcp/tests/responsive_prevalidate_export.rs b/crates/devup-mcp/tests/responsive_prevalidate_export.rs new file mode 100644 index 0000000..4a29469 --- /dev/null +++ b/crates/devup-mcp/tests/responsive_prevalidate_export.rs @@ -0,0 +1,171 @@ +//! `responsiveTsx` over frames that are not one screen costs nothing. +//! +//! The refusal used to live in projection, which runs after the collection it +//! needs. Asking for `responsiveTsx` over two frames of a Braillify Studio +//! Section spent 77 seconds and ten Figma reads before answering that the +//! snapshot had no mergeable breakpoint frames — a verdict the Section index +//! already held, because it lists every candidate's name and width. +//! +//! The index is in hand before the second call collects anything, so the +//! answer is due there. What this pins is the cost: the refusal arrives +//! without a single further read. + +use std::sync::{ + Arc, + atomic::{AtomicUsize, Ordering}, +}; + +use async_trait::async_trait; +use devup_mcp::server::{DevupAuth, DevupServer, Services}; +use devup_mcp_figma::{ + AuthStatus, BuiltinScript, DevupError, ErrorCode, FigmaUpstream, ReadToolCall, UpstreamResult, +}; +use rmcp::{ServiceExt, model::CallToolRequestParams}; +use serde_json::{Map, Value, json}; + +#[derive(Debug)] +struct ConnectedAuth; + +#[async_trait] +impl DevupAuth for ConnectedAuth { + async fn status(&self) -> Result { + Ok(AuthStatus::Connected) + } + async fn login(&self) -> Result { + Ok(AuthStatus::Connected) + } + async fn logout(&self) -> Result { + Ok(AuthStatus::Disconnected) + } +} + +/// A Section holding two different screens at two different widths — the +/// shape a caller reaches for when they want one responsive module and the +/// Section does not hold one. +fn section_index() -> UpstreamResult { + UpstreamResult { + raw: json!({ + "fileKey": "FileKey123", "version": null, "rootIds": ["10:1"], + "nodes": [ + {"id": "10:1", "type": "SECTION", "fields": { + "name": "로그인 화면", "parentId": "0:1", + "childrenIds": ["10:2", "10:3"], "visible": true, + "projectionTruncated": false, + "absoluteBoundingBox": {"x": 0, "y": 0, "width": 4000, "height": 2000} + }, "extra": {}, "fieldErrors": {}}, + {"id": "10:2", "type": "FRAME", "fields": { + "name": "AUTH-01", "parentId": "10:1", "childrenIds": [], "visible": true, + "directChildCount": 0, "subtreeNodeCount": 1, + "estimatedSerializedBytes": 1000, + "absoluteBoundingBox": {"x": 0, "y": 0, "width": 1920, "height": 1080} + }, "extra": {}, "fieldErrors": {}}, + {"id": "10:3", "type": "FRAME", "fields": { + "name": "AUTH-02", "parentId": "10:1", "childrenIds": [], "visible": true, + "directChildCount": 0, "subtreeNodeCount": 1, + "estimatedSerializedBytes": 1000, + "absoluteBoundingBox": {"x": 2100, "y": 0, "width": 375, "height": 812} + }, "extra": {}, "fieldErrors": {}} + ], "diagnostics": [] + }), + } +} + +/// Counts every read, and refuses to collect: reaching the collection at all +/// is the defect, so it is made loud rather than merely counted. +#[derive(Debug, Default)] +struct IndexOnlyUpstream(AtomicUsize); + +#[async_trait] +impl FigmaUpstream for IndexOnlyUpstream { + async fn list_tools(&self) -> Result, DevupError> { + Ok(vec!["use_figma".to_owned()]) + } + async fn call_read_tool(&self, call: ReadToolCall) -> Result { + self.0.fetch_add(1, Ordering::SeqCst); + match call { + ReadToolCall::Snapshot { + script: BuiltinScript::FastSnapshotEnvelope, + .. + } => Ok(section_index()), + _ => Err(DevupError::new( + ErrorCode::DevupSnapshotUnsupported, + "the family was decided from the index; nothing else may be collected", + false, + )), + } + } +} + +async fn call( + client: &rmcp::service::RunningService, + arguments: Value, +) -> anyhow::Result<(bool, Value)> { + let arguments: Map = arguments.as_object().cloned().unwrap(); + let result = client + .call_tool(CallToolRequestParams::new("devup_figma_export").with_arguments(arguments)) + .await?; + Ok(( + result.is_error == Some(true), + result + .structured_content + .expect("structured content either way"), + )) +} + +#[tokio::test] +async fn responsive_tsx_over_unrelated_frames_is_refused_without_collecting() -> anyhow::Result<()> +{ + let upstream = Arc::new(IndexOnlyUpstream::default()); + let server = DevupServer::new(Services::new(Arc::new(ConnectedAuth), upstream.clone())); + let (server_transport, client_transport) = tokio::io::duplex(256 * 1024); + let task = tokio::spawn(async move { + server.serve(server_transport).await?.waiting().await?; + anyhow::Ok(()) + }); + let client = ().serve(client_transport).await?; + let url = "https://www.figma.com/design/FileKey123/Fixture?node-id=10-1"; + + let (errored, selection) = call(&client, json!({"url": url, "outputs": ["tsx"]})).await?; + assert!(!errored, "{selection}"); + assert_eq!(selection["status"], "selection_required"); + let artifact_id = selection["cache"]["artifactId"] + .as_str() + .expect("the index is an artifact") + .to_owned(); + let after_index = upstream.0.load(Ordering::SeqCst); + + let (errored, refusal) = call( + &client, + json!({ + "artifactId": artifact_id, + "frameIds": ["10:2", "10:3"], + "outputs": ["responsiveTsx"], + }), + ) + .await?; + + // The defect, asserted before anything about wording: the same refusal + // used to arrive only after the frames had been collected in full. + assert_eq!( + upstream.0.load(Ordering::SeqCst), + after_index, + "the refusal must not cost a single Figma read" + ); + assert!( + errored, + "two unrelated screens are not one responsive module" + ); + let text = refusal.to_string(); + assert!( + text.contains("responsiveTsx"), + "the refusal names the output it refused: {text}" + ); + assert!( + text.contains("Nothing was collected"), + "the refusal says what it did not spend: {text}" + ); + + client.cancel().await?; + task.await??; + Ok(()) +} diff --git a/crates/devup-mcp/tests/skills.rs b/crates/devup-mcp/tests/skills.rs new file mode 100644 index 0000000..7d2d10f --- /dev/null +++ b/crates/devup-mcp/tests/skills.rs @@ -0,0 +1,112 @@ +use std::path::{Path, PathBuf}; + +use async_trait::async_trait; +use devup_mcp::skills::{FetchedSkill, SkillFetchError, SkillUpstream, check_with, install_with}; + +struct ScopedTempDir(PathBuf); + +impl ScopedTempDir { + fn new(label: &str) -> anyhow::Result { + let path = std::env::temp_dir().join(format!( + "devup-mcp-skills-{label}-{}-{}", + std::process::id(), + rand::random::() + )); + std::fs::create_dir_all(&path)?; + Ok(Self(path)) + } + + fn path(&self) -> &Path { + &self.0 + } +} + +impl Drop for ScopedTempDir { + fn drop(&mut self) { + let _ = std::fs::remove_dir_all(&self.0); + } +} + +struct FakeUpstream(Result); + +#[async_trait] +impl SkillUpstream for FakeUpstream { + async fn fetch(&self) -> Result { + self.0.clone() + } +} + +fn fetched(contents: &str, etag: &str) -> FetchedSkill { + FetchedSkill { + contents: contents.as_bytes().to_vec(), + etag: etag.to_owned(), + } +} + +#[tokio::test] +async fn provenance_distinguishes_up_to_date_from_stale() -> anyhow::Result<()> { + let target = ScopedTempDir::new("provenance")?; + let first = FakeUpstream(Ok(fetched("# v1\n", "\"etag-v1\""))); + let installed = install_with(&first, &[target.path().to_path_buf()], 1_789_171_200).await?; + assert_eq!(installed.targets[0].status, "installed"); + + let current = check_with(&first, &[target.path().to_path_buf()]).await?; + assert_eq!(current.targets[0].status, "up-to-date"); + + let changed = FakeUpstream(Ok(fetched("# v2\n", "\"etag-v2\""))); + let stale = check_with(&changed, &[target.path().to_path_buf()]).await?; + assert_eq!(stale.targets[0].status, "stale"); + + let provenance: serde_json::Value = serde_json::from_slice(&std::fs::read( + target.path().join("SKILL.md.provenance.json"), + )?)?; + assert_eq!(provenance["sourceUrl"], devup_mcp::skills::SKILL_SOURCE_URL); + assert_eq!(provenance["etag"], "\"etag-v1\""); + assert_eq!(provenance["fetchedAt"], 1_789_171_200_u64); + Ok(()) +} + +#[tokio::test] +async fn network_failure_is_actionable_and_writes_nothing() -> anyhow::Result<()> { + let target = ScopedTempDir::new("network")?; + let upstream = FakeUpstream(Err(SkillFetchError::Network( + "connection refused".to_owned(), + ))); + + let error = install_with(&upstream, &[target.path().to_path_buf()], 1) + .await + .unwrap_err(); + + assert!(error.to_string().contains("network")); + assert!(!target.path().join("SKILL.md").exists()); + Ok(()) +} + +#[tokio::test] +async fn missing_upstream_skill_reports_404_and_writes_nothing() -> anyhow::Result<()> { + let target = ScopedTempDir::new("not-found")?; + let upstream = FakeUpstream(Err(SkillFetchError::NotFound)); + + let error = install_with(&upstream, &[target.path().to_path_buf()], 1) + .await + .unwrap_err(); + + assert!(error.to_string().contains("404")); + assert!(!target.path().join("SKILL.md").exists()); + Ok(()) +} + +#[tokio::test] +async fn non_writable_target_keeps_skill_and_provenance_uncommitted() -> anyhow::Result<()> { + let target = ScopedTempDir::new("unwritable")?; + std::fs::create_dir(target.path().join("SKILL.md"))?; + let upstream = FakeUpstream(Ok(fetched("# skill\n", "\"etag\""))); + + let error = install_with(&upstream, &[target.path().to_path_buf()], 1) + .await + .unwrap_err(); + + assert!(error.to_string().contains("Cannot install devup-ui skill")); + assert!(!target.path().join("SKILL.md.provenance.json").exists()); + Ok(()) +} diff --git a/docs/r20/REPORT.md b/docs/r20/REPORT.md new file mode 100644 index 0000000..d697f32 --- /dev/null +++ b/docs/r20/REPORT.md @@ -0,0 +1,178 @@ +# R20 — 브라우저 실측 적용 대상 조사 + +**결론: 현재 확보한 캡처의 잔여 approximated 중 측정으로 판정을 결정할 수 +있는 대상은 0건이다. R20-2는 수행하지 않는다. 생성 TSX, 판정, 응답, +provenance 및 기본 export 동작은 변경하지 않는다.** + +## 기준과 조사 방법 + +브리프: `C:/Users/owjs3/orca/devup-mcp-briefs/R20-browser-measurement.md`. +작업 시작 HEAD `50afc95`는 로컬 main의 오래된 0.4.4였다. 원격을 fetch하고 +R6~R17 및 두 플랫폼 수정이 통합된 `origin/main` 0.4.5, +`0e01f96d6bde64e15118e1ff7f47cacf19430bd0`으로 fast-forward했다. + +조사는 다음 두 집합을 구분한다. + +1. 제품 코드에서 `Approximated`를 만들거나 보수적으로 복원하는 모든 경로. +2. 저장된 실제 캡처 및 축소 회귀 스냅샷을 현재 생성기로 재생한 결과. + 합성 테스트의 입력 변조는 실제 캡처의 미해결 건수로 세지 않는다. + +브라우저에서 수치를 얻는 것과 그 수치로 원본 대응을 판정하는 것은 다르다. +`측정 가능`은 알려진 원본 기대값과 실제 생성 결과를 비교해 해당 잔여 +판정을 결정할 수 있음을 뜻한다. `측정 불가`는 질문 자체가 CSS 측정 대상이 +아니거나 필요한 원본 증거가 없음을, `측정해도 판정 불가`는 출력 동작은 +측정할 수 있어도 남아 있는 원본 의도/외부 조건을 그 결과로 증명할 수 없음을 뜻한다. + +## 제품 코드 발생 경로 전수 목록 + +| 발생 경로 | 현재 근거 | 브라우저로 해결되지 않는 경우 | +|---|---|---| +| `codegen/component.rs` ABSOLUTE fallback, `provenance/sizing.rs::absolute_component_verification` | width/height/horizontal/vertical 각각 검증, 미해결 축이 있으면 근사 유지 | 원본 치수/제약 읽기 실패, 외부 containing block, 상속 제약 | +| `provenance/absolute_bounds.rs::annotate` | export boundary, rounding, constraintInterpretation을 별도 검증 | render boundary의 선택과 GROUP 의도의 불명확성을 픽셀 일치로 상쇄할 수 없음 | +| `codegen/evidence.rs::placement_contract` | 생성물에 포함되지 않은 외부 호스트 또는 미확정 루트 치수 | 만든 테스트 호스트가 사용자의 실제 호스트라는 증거가 없음 | +| `codegen/component.rs::non_rendering_diagnostic` | visible/render bounds를 오류 없이 수집했는지 | 누락된 원본 paint를 빈 출력의 관측으로 복구할 수 없음 | +| `DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED` | 변수/스타일의 원본 ID를 이름에 대응하지 못함 | 동일한 현재 색/치수는 토큰 정체성이나 테마 추종의 증거가 아님 | +| `devup-mcp-figma/src/snapshot.rs::Diagnostic::fidelity_impact` | 명시 impact가 없는 ABSOLUTE 또는 미등록 codegen 경고를 보수적으로 근사 처리 | 알 수 없는 경고의 의미를 브라우저 통과만으로 지울 수 없음 | +| `provenance.rs::validate_fidelity` | 기존 VERIFIED ABSOLUTE 또는 NON_RENDERING 주장을 최종 출력에서 다시 검사, 실패 시 근사 복원 | 조작/오래된 라벨을 신뢰하지 않는 R13/R17 보호 경로; 새로운 수집 증거 없이 해제 불가 | + +치수 판정의 미해결 이유도 전부 확인했다: `read-error`, +`conflicting-dimension-props`, `intrinsic-layout-unproven`, `non-fixed-sizing`, +`source-dimension-unknown`, `generated-dimension-unproven`, +`parent-width-unknown`, `parent-height-unknown`, `parent-width-unequal`, +`parent-height-unequal`, `parent-padding-or-border`, `containing-block-unproven`. +자산 경계 경로에는 `export-boundary-unproven`, `rounded-dimension-mismatch`가 추가된다. +이 enum/분기들이 존재한다는 사실만으로 실측할 실제 잔여 사례가 존재한다고 세지 않는다. + +`MASK_FALLBACK`, `EFFECT_FALLBACK`, `ANIMATION_UNREACHABLE`, +`VARIANT_CHILD_FALLBACK`, 미대응 layout/property는 lossy 계열이다. +정상 자동 텍스트는 R10 이후 impact none이며, 실패한 content-sizing 경로만 +lossy다. 기존 R7 문서의 “자동 텍스트는 lossy”를 현재 상태로 오독하면 안 된다. + +## 실제 재생 결과와 후보 분류 + +저장소의 `fixtures` 및 `crates/devup-mcp-devup-ui/tests/fixtures`에서 JSON을 +열어 최상위 또는 `snapshot` 안에 nodes/roots가 있는 파일 22개를 전부 선정했다. +여기에 외부 R14 검증의 24노드 전체 snapshot 1개를 추가했다. +각 snapshot의 roots와 SECTION 직계 자식을 중복 제거하고, +`inlineInstances=false/true`, 기본 standalone으로 **62개 출력**을 재생했다. +62개 모두 생성 성공, 생성 오류 0건이다. fixture별 루트, 옵션, impact와 +진단 원문은 [inventory.json](inventory.json)에 있다. 서로 겹치는 캡처와 두 +출력 모드를 포함한 **관측 건수**이며 독립적인 디자인 결함 수가 아니다. + +| 진단/근거 | 관측 수 | 고유 대상과 현재 판정 | 분류 및 이유 | +|---|---:|---|---| +| ABSOLUTE fallback | 4 | 축소/전체 snapshot × inline 2종. `3997:46668`의 horizontal/vertical만 unresolved | **측정해도 판정 불가**. 두 축 모두 GROUP 원본 제약이 아니라 first-child 상속이며 assumed다. 수치 관측으로 상속 정책이 원본 의도인지를 증명할 수 없다. | +| NON_RENDERING_ASSET | 4 | R9 단일 노드와 R2 WQUW-119의 `3997:46703` × 2. `no-render-bounds`, fieldPresent=false | **측정 불가**. 누락된 Figma render bounds를 생성된 숨김/빈 요소 측정으로 복구할 수 없다. 재수집이 필요하다. | +| TOKEN_NAME_UNRESOLVED | 298 | 147개 고유 node/property/resourceId 조합, impact의 기본 경고 분류는 approximated | **측정 불가**. 변수·스타일 이름/정체성은 픽셀 메트릭이 아니다. 모두 리소스 카탈로그 없는 raw/reduced snapshot 입력에서 관측됐다. 실제 앱 export에 298개 결함이 있다는 뜻이 아니다. | +| LAYOUT_ACCOUNTED_FOR | 18 | content-sizing 및 기존 implicit sizing 근거, impact none | 잔여 근사에 포함하지 않는다. 아래 자동 텍스트 설명 참조. | +| PLACEMENT_CONTRACT | 0 (근사) | 이번 standalone 재생에서는 근사 없음. embedded/외부 호스트 조건 분기는 코드와 기존 회귀에서 확인 | **측정해도 판정 불가**(미제공 호스트). 임의로 만든 호스트에서의 일치가 소비 앱의 호스트 조건 충족을 증명하지 않는다. | +| 미등록 경고/최종 재검증 강등 | 0 (현재 재생) | 코드 발생 경로 및 기존 반례 테스트로 확인 | **측정 불가**(미등록 경고 의미), **측정해도 판정 불가**(잘못된 provenance). 브라우저 일치가 source mapping 변조나 원본 수집 오류를 복원하지 않는다. | + +알려진 후보를 실제 필드로 채우면 다음과 같다. + +| 후보 | 실제 원본/출력 | 판정 가능성 | +|---|---|---| +| `text-auto-size` | 예: `I3997:46130;65:2919` width/height는 R10의 `accounted-for-content-sizing`, impact none, `font-metrics-not-measured` 유지 | **폰트/치수 자체는 측정 가능**, 그러나 현재 approximated를 끊을 대상은 아님. 원본 글꼴 로딩·glyph fallback·실제 devup-ui CSS를 확인한 조건부 픽셀 비교라는 별도 과제로 남긴다. 폰트 미설치를 핑계로 “측정 불가능”으로 분류하지 않았다. | +| `3997:46668` 가로 | GROUP width=433.8122863769531, render width=360, local x=-19, render-relative left=0px. 첫 자식 `3997:46669`의 SCALE 사용 | **측정해도 판정 불가**. 고정 360px/left 0의 반응은 관측 가능하지만 GROUP 자체 SCALE 기대값이 없다. 자식 SCALE을 참이라고 가정한 조건부 불일치를 GROUP의 확정 손실로 보고하지 않는다. | +| `3997:46668` 세로 | parent height=460, render-relative y=314, render height=117.6744155883789 → bottom=28.33px. 첫 자식 MAX 사용 | **측정해도 판정 불가**. 부모 높이에 따른 하단 여백 유지 여부를 관측할 수 있어도 GROUP의 MAX 의도는 미확인이다. | +| 잔여 ABSOLUTE 폭/높이 | 62개 출력에서 근사 폭/높이 0건. R14 모달 `3997:46621` 및 자산 폭/높이는 이미 정적 검증됨 | 현재 **측정으로 해제할 잔여 없음**. 합성 fixture 변조로 새 측정 대상을 만들지 않았다. | +| `boundaryDeltaPixels` | width: 360−433.8122863769531=−73.8122863769531. height: render/source 동일, CSS 117.67px의 serializer 오차 약 0.0044155884px | 선택 경계의 CSS box 치수는 **측정 가능**하나 대응은 이미 verified다. 실제 자산 paint/SVG 합성의 등가성은 이 snapshot의 경계 숫자만으로 **측정해도 판정 불가**. box rect가 paint bounds와 같다고 가정하지 않는다. | + +원본 ABSOLUTE 선언의 사전 조사에서는 저장소 22개 snapshot에 33개 노드 +관측이 있었다(캡처 중복 포함): CENTER/MIN 11, MAX/MIN 13, MIN/MAX 8, +GROUP 자체 제약 없음 1. 직접 SCALE/STRETCH를 선언한 실제 ABSOLUTE 캡처는 +없었다. R9 테스트는 모달 constraints와 width를 **의도적으로 변조**해 +SCALE/STRETCH/MAX 및 400px 반례를 만든다. 알려진 직접 제약/기대값을 갖는 +이런 사례라면 향후 실제 CSS의 resize 측정으로 조건부 손실을 확인할 수 있다. +하지만 합성 반례를 현재 캡처에 남은 실측 대상인 것처럼 세지 않는다. + +전체 snapshot은 다음 파일의 바이트 그대로 복사했다. 원본 저장소는 읽기만 했다. + +`C:/Users/owjs3/orca/workspaces/girok-space/wquw-118-fr007-question-trial-send/docs/verify-r14/rawSnapshot.json` + +SHA-256: `E57E99A814F26D45B769E656DD0B581D2011B1997F94FEDCAD97BCB8F81B1D67`. +해당 디렉터리 REPORT와 이전 R13 원문 응답도 대조했다. 새로운 Figma 수집이나 +설치된 MCP 호출이 아니다. 전체 snapshot에는 카탈로그/자산 바이너리가 없으므로 +그 누락으로 발생한 token 경고와 inline=false의 component-reference 손실은 +GROUP 축 판정과 분리한다. + +## R7-2 전례의 재사용 가능성 + +`docs/R7-report.md`와 `docs/R7-verification.txt`, 관련 fixture 및 +`tests/r7_layout.rs`를 확인했다. 보고된 Edge 관측은 부모 56/기존 55/stretch 56, +부모 80/기존 55/stretch 80이다. 이 라운드에서 다시 측정한 값은 아니다. +저장소의 추적 파일에는 당시 headless 실행 스크립트나 HTML이 없다. +따라서 방법의 재현은 가능하나 기존 스크립트를 그대로 재사용했다고 주장할 수 없다. +R7의 FILL에는 알려진 크기 추종 의도가 있었으며, 그 점이 원본 GROUP 의도나 +토큰 정체성이 누락된 문제와 다르다. + +별도의 기존 `harness/render`에는 Vite + devup-ui + Playwright Chromium으로 +생성 TSX를 렌더하는 경로와 `boxes.mjs`의 getBoundingClientRect/getComputedStyle +관측이 있다. 이 방식은 실제 CSS를 실행한다는 점에서 재사용할 수 있다. +다만 현재 boxes는 정수 반올림, 화면 깊이/텍스트 기준 식별, Windows taskkill +정리이며 sourceMap의 노드/축 판정과 연결되지 않는다. `acquire.py`는 설치된 +`~/.cargo/bin/devup-mcp.exe`를 명시하므로 이번 검증에서는 실행하지 않았다. +이 기존 harness의 존재를 신규 opt-in 판정 파이프라인 완성으로 세지 않는다. + +## 측정 한계 + +이번 조사에서 브라우저를 실행하거나 폰트/픽셀을 측정했다고 주장하지 않는다. +향후 측정에서도 폰트 로딩 및 실제 glyph fallback, viewport와 호스트 CSS, +브라우저 엔진 버전을 조건으로 기록해야 한다. 폰트 또는 브라우저가 없으면 +미측정/실패로 남기고 정적 판정을 유지해야 한다. 특정 환경의 일치는 모든 +환경의 픽셀·반응형 등가성이나 source provenance의 증명이 아니다. + +## 재현과 변경 범위 + +`inventory.rs`는 제품 구현이 아닌 조사 시 사용한 읽기 전용 재생 프로그램이다. +`inputs.txt`는 입력 23개의 목록이다. 저장된 payload는 자기 리소스를, +snapshot/resources wrapper는 wrapper의 리소스를 사용한다. raw snapshot은 +추가 카탈로그를 합성하거나 다른 시점의 캡처에서 가져오지 않는다. +따라서 R6의 별도 token-name fixture도 이 raw-only 재생에는 주입하지 않았다. +이 선택은 토큰 경고의 수에 영향을 주며 위 표에 그 한계를 명시했다. + +조사를 재현하려면 저장소 루트에서 `inventory.rs`를 임시로 +`crates/devup-mcp-devup-ui/examples/r20_inventory.rs`에 복사한 다음 실행한다. + +```powershell +$r20Inputs = Get-Content docs/r20/inputs.txt +cargo run -j 2 -p devup-mcp-devup-ui --example r20_inventory -- $r20Inputs +``` + +저장된 inventory의 fixture 경로에는 실행 당시 Windows 구분자가 남아 있다. +inputs 목록은 다른 OS에서도 사용할 수 있도록 `/`로 정규화했다. +실행 파일은 이번 작업 트리의 target에서 빌드했으며 설치된 MCP는 호출하지 않았다. + +측정 가능 잔여가 0건이므로 R20-2 구현이나 제품 버그 수정이 없다. +이에 따라 새 실패 테스트를 인위적으로 만들지 않았다. 기존 실패 테스트 삭제, +assertion 약화, golden 변경 모두 0건이다. 임시 예제 코드는 조사 자료로만 +보존하고 crate의 빌드 대상에는 남기지 않는다. R6~R17의 판정·안내, +R13/R17 provenance, R14 widthPreservation/componentSummary, +R11 SECTION 상한은 원본 코드 및 기존 회귀를 그대로 유지한다. + +CI의 ubuntu-latest/macos-latest/windows-latest 행렬을 확인했다. +새 브라우저·폰트·프로세스 의존성, 환경변수, 플랫폼별 파일 경로 처리 또는 +CI 변경은 없다. Windows에서 직접 검증하며 Ubuntu/macOS 실행은 미확인이다. +기존 harness의 플랫폼 제약을 이번 제품 경로로 가져오지 않았다. + +## 검증 결과 + +- `cargo test --workspace -j 2 --no-fail-fast`: **855 passed / 0 failed / 2 ignored**, exit 0. +- `node --test crates/devup-mcp-figma/tests/explore_script_behavior.mjs`: **13 passed / 0 failed**, exit 0. +- `cargo clippy --workspace --all-targets -j 2 -- -D warnings`: exit 0, 경고 0. +- `cargo fmt --all -- --check`: exit 0. 임시 예제를 문서로 옮긴 최종 상태에서도 통과. +- 자체 `target/debug/devup-mcp.exe --version`: `0.4.5 (0e01f96d6bde-dirty)`. + `--self-check`: status ok. 임베디드 commit만으로 검증을 주장하지 않고 + [target-identity.json](target-identity.json)에 실제 경로와 SHA-256을 기록했다. +- 해당 target의 `r14_absolute_evidence-6e04826c1505b9df.exe`에서 + `r14_asset_boundary_rounding_and_inherited_constraints_are_separate --exact` + 직접 실행: 1 passed / 0 failed. [local-test.txt](local-test.txt). +- 최초 전체 빌드는 조사를 먼저 실행하도록 순서를 바꾸기 위해 중단했다. + 이후 요구된 전체 명령을 다시 실행한 완결 로그가 [workspace-tests.txt](workspace-tests.txt)다. + Windows 테스트 링크 중 import library 생성 안내가 `linker_messages` 경고로 + 출력됐지만 전체 exit 0이며 별도 clippy는 `-D warnings`로 통과했다. + +**자기 target 에서 검증했고 실행된 테스트가 내 것임을 확인했다.** +`CARGO_TARGET_DIR`는 설정하지 않았다. 컴파일하는 cargo 명령에는 모두 `-j 2`를 +사용했다. fmt/metadata/clean은 해당 옵션을 받지 않는 명령이다. +최종 전달은 로컬 커밋 후 cargo clean이며 push는 하지 않는다. diff --git a/docs/r20/asset-full-snapshot.json b/docs/r20/asset-full-snapshot.json new file mode 100644 index 0000000..987a183 --- /dev/null +++ b/docs/r20/asset-full-snapshot.json @@ -0,0 +1,1877 @@ +{ + "fileKey": "85CgSws3o5XsLv7aAwWJyS", + "version": null, + "roots": [ + "3997:46667" + ], + "nodes": { + "3997:46667": { + "id": "3997:46667", + "type": "FRAME", + "fields": { + "parentId": "4279:7806", + "parentType": "SECTION", + "parentName": "[FR-07~09] 질문 체험하기", + "childrenIds": [ + "3997:46668", + "3997:46670", + "3997:46681" + ], + "absoluteBoundingBox": { + "height": 460, + "width": 360, + "x": 19263, + "y": 16557 + }, + "absoluteRenderBounds": { + "height": 460, + "width": 360, + "x": 19263, + "y": 16557 + }, + "bottomLeftRadius": 0, + "bottomRightRadius": 0, + "boundVariables": { + "fills": [ + { + "id": "VariableID:1:1000", + "type": "VARIABLE_ALIAS" + } + ] + }, + "clipsContent": true, + "constraints": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "fills": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:1000", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 1, + "g": 1, + "r": 1 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "height": 460, + "inferredAutoLayout": { + "counterAxisAlignItems": "MIN", + "counterAxisSizingMode": "FIXED", + "itemSpacing": 24, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutMode": "VERTICAL", + "layoutPositioning": "AUTO", + "paddingBottom": 24, + "paddingLeft": 20, + "paddingRight": 20, + "paddingTop": 24, + "primaryAxisAlignItems": "MIN", + "primaryAxisSizingMode": "FIXED" + }, + "itemSpacing": 24, + "layoutGrow": 0, + "layoutMode": "VERTICAL", + "layoutWrap": "NO_WRAP", + "layoutPositioning": "AUTO", + "layoutSizingHorizontal": "FIXED", + "layoutSizingVertical": "FIXED", + "maxHeight": null, + "maxWidth": null, + "name": "Frame 1321314919", + "opacity": 1, + "overflowDirection": "NONE", + "paddingBottom": 24, + "paddingLeft": 20, + "paddingRight": 20, + "paddingTop": 24, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1, + "strokeTopWeight": 1, + "strokeWeight": 1, + "topLeftRadius": 0, + "topRightRadius": 0, + "visible": true, + "width": 360, + "x": 4934, + "y": 1934 + }, + "extra": {}, + "fieldErrors": {} + }, + "3997:46668": { + "id": "3997:46668", + "type": "GROUP", + "fields": { + "parentId": "3997:46667", + "childrenIds": [ + "3997:46669" + ], + "absoluteBoundingBox": { + "height": 117.6744155883789, + "width": 433.8122863769531, + "x": 19244, + "y": 16871 + }, + "absoluteRenderBounds": { + "height": 117.6744155883789, + "width": 360, + "x": 19263, + "y": 16871 + }, + "height": 117.6744155883789, + "layoutGrow": 0, + "layoutPositioning": "ABSOLUTE", + "layoutSizingHorizontal": "FIXED", + "layoutSizingVertical": "FIXED", + "maxHeight": null, + "maxWidth": null, + "name": "Design", + "opacity": 1, + "visible": true, + "width": 433.8122863769531, + "x": -19, + "y": 314 + }, + "extra": {}, + "fieldErrors": {} + }, + "3997:46669": { + "id": "3997:46669", + "type": "VECTOR", + "fields": { + "parentId": "3997:46668", + "absoluteBoundingBox": { + "height": 117.6744155883789, + "width": 433.8122863769531, + "x": 19244, + "y": 16871 + }, + "absoluteRenderBounds": { + "height": 117.673828125, + "width": 360, + "x": 19263, + "y": 16871 + }, + "boundVariables": { + "fills": [ + { + "id": "VariableID:278:3649", + "type": "VARIABLE_ALIAS" + } + ] + }, + "constraints": { + "horizontal": "SCALE", + "vertical": "MAX" + }, + "fills": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:278:3649", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.8907090425491333, + "g": 0.9080576300621032, + "r": 0.9278846383094788 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "height": 117.6744155883789, + "layoutGrow": 0, + "layoutPositioning": "AUTO", + "layoutSizingHorizontal": "FIXED", + "layoutSizingVertical": "FIXED", + "maxHeight": null, + "maxWidth": null, + "name": "Vector", + "opacity": 1, + "strokeWeight": 1, + "visible": true, + "width": 433.8122863769531, + "x": -19, + "y": 314 + }, + "extra": {}, + "fieldErrors": {} + }, + "3997:46670": { + "id": "3997:46670", + "type": "FRAME", + "fields": { + "parentId": "3997:46667", + "childrenIds": [ + "3997:46671", + "3997:46680" + ], + "absoluteBoundingBox": { + "height": 156, + "width": 320, + "x": 19283, + "y": 16581 + }, + "absoluteRenderBounds": { + "height": 156, + "width": 320, + "x": 19283, + "y": 16581 + }, + "bottomLeftRadius": 0, + "bottomRightRadius": 0, + "constraints": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "counterAxisAlignItems": "CENTER", + "height": 156, + "inferredAutoLayout": { + "counterAxisAlignItems": "CENTER", + "counterAxisSizingMode": "FIXED", + "itemSpacing": 12, + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutMode": "VERTICAL", + "layoutPositioning": "AUTO", + "paddingBottom": 0, + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "primaryAxisAlignItems": "MIN", + "primaryAxisSizingMode": "AUTO" + }, + "itemSpacing": 12, + "layoutGrow": 0, + "layoutMode": "VERTICAL", + "layoutWrap": "NO_WRAP", + "layoutPositioning": "AUTO", + "layoutSizingHorizontal": "FILL", + "layoutSizingVertical": "HUG", + "maxHeight": null, + "maxWidth": null, + "name": "Frame 1321315561", + "opacity": 1, + "overflowDirection": "NONE", + "paddingBottom": 0, + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1, + "strokeTopWeight": 1, + "strokeWeight": 1, + "topLeftRadius": 0, + "topRightRadius": 0, + "visible": true, + "width": 320, + "x": 20, + "y": 24 + }, + "extra": {}, + "fieldErrors": {} + }, + "3997:46671": { + "id": "3997:46671", + "type": "FRAME", + "fields": { + "parentId": "3997:46670", + "childrenIds": [ + "3997:46672" + ], + "absoluteBoundingBox": { + "height": 48, + "width": 48, + "x": 19419, + "y": 16581 + }, + "absoluteRenderBounds": { + "height": 48, + "width": 48, + "x": 19419, + "y": 16581 + }, + "bottomLeftRadius": 12, + "bottomRightRadius": 12, + "boundVariables": { + "fills": [ + { + "id": "VariableID:1:995", + "type": "VARIABLE_ALIAS" + } + ] + }, + "constraints": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerRadius": 12, + "fills": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:995", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.1764705926179886, + "g": 0.1764705926179886, + "r": 0.4588235318660736 + }, + "opacity": 1, + "type": "SOLID", + "visible": false + } + ], + "height": 48, + "itemSpacing": 0, + "layoutGrow": 0, + "layoutMode": "NONE", + "layoutWrap": "NO_WRAP", + "layoutPositioning": "AUTO", + "layoutSizingHorizontal": "FIXED", + "layoutSizingVertical": "FIXED", + "maxHeight": null, + "maxWidth": null, + "name": "Favicon", + "opacity": 1, + "overflowDirection": "NONE", + "paddingBottom": 0, + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1, + "strokeTopWeight": 1, + "strokeWeight": 1, + "targetAspectRatio": { + "x": 160, + "y": 160 + }, + "topLeftRadius": 12, + "topRightRadius": 12, + "visible": true, + "width": 48, + "x": 136, + "y": 0 + }, + "extra": {}, + "fieldErrors": {} + }, + "3997:46672": { + "id": "3997:46672", + "type": "FRAME", + "fields": { + "parentId": "3997:46671", + "childrenIds": [ + "3997:46673" + ], + "absoluteBoundingBox": { + "height": 18.90010643005371, + "width": 36, + "x": 19425, + "y": 16595.69921875 + }, + "absoluteRenderBounds": { + "height": 18.900390625, + "width": 36, + "x": 19425, + "y": 16595.69921875 + }, + "bottomLeftRadius": 0, + "bottomRightRadius": 0, + "constraints": { + "horizontal": "SCALE", + "vertical": "SCALE" + }, + "height": 18.90010643005371, + "isAsset": true, + "itemSpacing": 0, + "layoutGrow": 0, + "layoutMode": "NONE", + "layoutWrap": "NO_WRAP", + "layoutPositioning": "AUTO", + "layoutSizingHorizontal": "FIXED", + "layoutSizingVertical": "FIXED", + "maxHeight": null, + "maxWidth": null, + "name": "Frame 424", + "opacity": 1, + "overflowDirection": "NONE", + "paddingBottom": 0, + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1, + "strokeTopWeight": 1, + "strokeWeight": 1, + "topLeftRadius": 0, + "topRightRadius": 0, + "visible": true, + "width": 36, + "x": 5.999707221984863, + "y": 14.69970703125 + }, + "extra": {}, + "fieldErrors": {} + }, + "3997:46673": { + "id": "3997:46673", + "type": "BOOLEAN_OPERATION", + "fields": { + "parentId": "3997:46672", + "childrenIds": [ + "3997:46674", + "3997:46675", + "3997:46676", + "3997:46677", + "3997:46678", + "3997:46679" + ], + "absoluteBoundingBox": { + "height": 18.900190353393555, + "width": 36, + "x": 19425, + "y": 16595.69921875 + }, + "absoluteRenderBounds": { + "height": 18.900390625, + "width": 36, + "x": 19425, + "y": 16595.69921875 + }, + "boundVariables": { + "fills": [ + { + "id": "VariableID:1:995", + "type": "VARIABLE_ALIAS" + } + ] + }, + "fills": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:995", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.1764705926179886, + "g": 0.1764705926179886, + "r": 0.4588235318660736 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "height": 18.900190353393555, + "layoutGrow": 0, + "layoutPositioning": "AUTO", + "layoutSizingHorizontal": "FIXED", + "layoutSizingVertical": "FIXED", + "maxHeight": null, + "maxWidth": null, + "name": "Union", + "opacity": 1, + "strokeWeight": 0, + "visible": true, + "width": 36, + "x": 0, + "y": 0 + }, + "extra": {}, + "fieldErrors": {} + }, + "3997:46674": { + "id": "3997:46674", + "type": "VECTOR", + "fields": { + "parentId": "3997:46673", + "absoluteBoundingBox": { + "height": 4.400611877441406, + "width": 36, + "x": 19425, + "y": 16610.19921875 + }, + "absoluteRenderBounds": null, + "constraints": { + "horizontal": "SCALE", + "vertical": "SCALE" + }, + "fills": [ + { + "blendMode": "NORMAL", + "boundVariables": {}, + "color": { + "b": 0.17999267578125, + "g": 0.17999267578125, + "r": 0.4589996337890625 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "height": 4.400611877441406, + "layoutGrow": 0, + "layoutPositioning": "AUTO", + "layoutSizingHorizontal": "FIXED", + "layoutSizingVertical": "FIXED", + "maxHeight": null, + "maxWidth": null, + "name": "Vector", + "opacity": 1, + "strokeWeight": 1, + "visible": true, + "width": 36, + "x": 0.0001441887579858303, + "y": 14.499555587768556 + }, + "extra": {}, + "fieldErrors": {} + }, + "3997:46675": { + "id": "3997:46675", + "type": "VECTOR", + "fields": { + "parentId": "3997:46673", + "absoluteBoundingBox": { + "height": 10.009685516357422, + "width": 15.76115608215332, + "x": 19442.60546875, + "y": 16603.654296875 + }, + "absoluteRenderBounds": null, + "constraints": { + "horizontal": "SCALE", + "vertical": "SCALE" + }, + "fills": [ + { + "blendMode": "NORMAL", + "boundVariables": {}, + "color": { + "b": 0.17999267578125, + "g": 0.17999267578125, + "r": 0.4589996337890625 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "height": 10.009685516357422, + "layoutGrow": 0, + "layoutPositioning": "AUTO", + "layoutSizingHorizontal": "FIXED", + "layoutSizingVertical": "FIXED", + "maxHeight": null, + "maxWidth": null, + "name": "Vector", + "opacity": 1, + "strokeWeight": 1, + "visible": true, + "width": 15.76115608215332, + "x": 17.60617446899414, + "y": 7.95412015914917 + }, + "extra": {}, + "fieldErrors": {} + }, + "3997:46676": { + "id": "3997:46676", + "type": "VECTOR", + "fields": { + "parentId": "3997:46673", + "absoluteBoundingBox": { + "height": 15.75329875946045, + "width": 10.014678955078123, + "x": 19442.31640625, + "y": 16597.619140625 + }, + "absoluteRenderBounds": null, + "constraints": { + "horizontal": "SCALE", + "vertical": "SCALE" + }, + "fills": [ + { + "blendMode": "NORMAL", + "boundVariables": {}, + "color": { + "b": 0.17999267578125, + "g": 0.17999267578125, + "r": 0.4589996337890625 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "height": 15.75329875946045, + "layoutGrow": 0, + "layoutPositioning": "AUTO", + "layoutSizingHorizontal": "FIXED", + "layoutSizingVertical": "FIXED", + "maxHeight": null, + "maxWidth": null, + "name": "Vector", + "opacity": 1, + "strokeWeight": 1, + "visible": true, + "width": 10.014678955078123, + "x": 17.31575584411621, + "y": 1.9202334880828855 + }, + "extra": {}, + "fieldErrors": {} + }, + "3997:46677": { + "id": "3997:46677", + "type": "VECTOR", + "fields": { + "parentId": "3997:46673", + "absoluteBoundingBox": { + "height": 17.278425216674805, + "width": 1.5830192565917969, + "x": 19442.208984375, + "y": 16595.69921875 + }, + "absoluteRenderBounds": null, + "constraints": { + "horizontal": "SCALE", + "vertical": "SCALE" + }, + "fills": [ + { + "blendMode": "NORMAL", + "boundVariables": {}, + "color": { + "b": 0.17999267578125, + "g": 0.17999267578125, + "r": 0.4589996337890625 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "height": 17.278425216674805, + "layoutGrow": 0, + "layoutPositioning": "AUTO", + "layoutSizingHorizontal": "FIXED", + "layoutSizingVertical": "FIXED", + "maxHeight": null, + "maxWidth": null, + "name": "Vector", + "opacity": 1, + "strokeWeight": 1, + "visible": true, + "width": 1.5830192565917969, + "x": 17.208635330200195, + "y": 0.00014426291454583406 + }, + "extra": {}, + "fieldErrors": {} + }, + "3997:46678": { + "id": "3997:46678", + "type": "VECTOR", + "fields": { + "parentId": "3997:46673", + "absoluteBoundingBox": { + "height": 15.75329875946045, + "width": 10.014678955078123, + "x": 19433.671875, + "y": 16597.619140625 + }, + "absoluteRenderBounds": null, + "constraints": { + "horizontal": "SCALE", + "vertical": "SCALE" + }, + "fills": [ + { + "blendMode": "NORMAL", + "boundVariables": {}, + "color": { + "b": 0.17999267578125, + "g": 0.17999267578125, + "r": 0.4589996337890625 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "height": 15.75329875946045, + "layoutGrow": 0, + "layoutPositioning": "AUTO", + "layoutSizingHorizontal": "FIXED", + "layoutSizingVertical": "FIXED", + "maxHeight": null, + "maxWidth": null, + "name": "Vector", + "opacity": 1, + "strokeWeight": 1, + "visible": true, + "width": 10.014678955078123, + "x": 8.672233581542969, + "y": 1.9202334880828855 + }, + "extra": {}, + "fieldErrors": {} + }, + "3997:46679": { + "id": "3997:46679", + "type": "VECTOR", + "fields": { + "parentId": "3997:46673", + "absoluteBoundingBox": { + "height": 10.009685516357422, + "width": 15.76115608215332, + "x": 19427.634765625, + "y": 16603.654296875 + }, + "absoluteRenderBounds": null, + "constraints": { + "horizontal": "SCALE", + "vertical": "SCALE" + }, + "fills": [ + { + "blendMode": "NORMAL", + "boundVariables": {}, + "color": { + "b": 0.17999267578125, + "g": 0.17999267578125, + "r": 0.4589996337890625 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "height": 10.009685516357422, + "layoutGrow": 0, + "layoutPositioning": "AUTO", + "layoutSizingHorizontal": "FIXED", + "layoutSizingVertical": "FIXED", + "maxHeight": null, + "maxWidth": null, + "name": "Vector", + "opacity": 1, + "strokeWeight": 1, + "visible": true, + "width": 15.76115608215332, + "x": 2.6353354454040527, + "y": 7.95412015914917 + }, + "extra": {}, + "fieldErrors": {} + }, + "3997:46680": { + "id": "3997:46680", + "type": "TEXT", + "fields": { + "parentId": "3997:46670", + "absoluteBoundingBox": { + "height": 96, + "width": 320, + "x": 19283, + "y": 16641 + }, + "absoluteRenderBounds": { + "height": 79.626953125, + "width": 263.859375, + "x": 19308.6640625, + "y": 16648.796875 + }, + "boundVariables": { + "fills": [ + { + "id": "VariableID:1:998", + "type": "VARIABLE_ALIAS" + } + ] + }, + "characters": "한 편을 읽고 나면, 더 묻고 싶어집니다. 
이 사람의 이야기를 더 듣고 싶다면 
기록공간을 선물해 보세요.", + "constraints": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "fills": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:998", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.19891290366649628, + "g": 0.19891290366649628, + "r": 0.21474339067935944 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "fontName": { + "family": "Pretendard", + "style": "Regular" + }, + "fontSize": 18, + "height": 96, + "layoutGrow": 0, + "layoutPositioning": "AUTO", + "layoutSizingHorizontal": "FILL", + "layoutSizingVertical": "HUG", + "letterSpacing": { + "unit": "PERCENT", + "value": -1 + }, + "lineHeight": { + "unit": "PERCENT", + "value": 179.99999523162842 + }, + "maxHeight": null, + "maxWidth": null, + "name": "한 편을 읽고 나면, 더 묻고 싶어집니다. 
이 사람의 이야기를 더 듣고 싶다면 
기록공간을 선물해 보세요.", + "opacity": 1, + "strokeAlign": "OUTSIDE", + "strokeWeight": 1, + "textAlignHorizontal": "CENTER", + "textAutoResize": "HEIGHT", + "textStyleId": "S:3dbbcdf26742b272a0f23eae240c9bbebd5089b8,", + "textTruncation": "DISABLED", + "visible": true, + "width": 320, + "x": 0, + "y": 60, + "styledTextSegments": [ + { + "characters": "한 편을 읽고 나면, 더 묻고 싶어집니다. 
이 사람의 이야기를 더 듣고 싶다면 
기록공간을 선물해 보세요.", + "end": 60, + "fillStyleId": "", + "fontWeight": 400, + "hyperlink": null, + "indentation": 0, + "listOptions": { + "type": "NONE" + }, + "start": 0, + "textStyleId": "S:3dbbcdf26742b272a0f23eae240c9bbebd5089b8," + } + ] + }, + "extra": {}, + "fieldErrors": {} + }, + "3997:46681": { + "id": "3997:46681", + "type": "FRAME", + "fields": { + "parentId": "3997:46667", + "childrenIds": [ + "3997:46682", + "3997:46683" + ], + "absoluteBoundingBox": { + "height": 118, + "width": 320, + "x": 19283, + "y": 16761 + }, + "absoluteRenderBounds": { + "height": 118, + "width": 320, + "x": 19283, + "y": 16761 + }, + "bottomLeftRadius": 0, + "bottomRightRadius": 0, + "constraints": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "height": 118, + "inferredAutoLayout": { + "counterAxisAlignItems": "MIN", + "counterAxisSizingMode": "FIXED", + "itemSpacing": 8, + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutMode": "VERTICAL", + "layoutPositioning": "AUTO", + "paddingBottom": 0, + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "primaryAxisAlignItems": "MIN", + "primaryAxisSizingMode": "AUTO" + }, + "itemSpacing": 8, + "layoutGrow": 0, + "layoutMode": "VERTICAL", + "layoutWrap": "NO_WRAP", + "layoutPositioning": "AUTO", + "layoutSizingHorizontal": "FILL", + "layoutSizingVertical": "HUG", + "maxHeight": null, + "maxWidth": null, + "name": "Frame 1321315560", + "opacity": 1, + "overflowDirection": "NONE", + "paddingBottom": 0, + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1, + "strokeTopWeight": 1, + "strokeWeight": 1, + "topLeftRadius": 0, + "topRightRadius": 0, + "visible": true, + "width": 320, + "x": 20, + "y": 204 + }, + "extra": {}, + "fieldErrors": {} + }, + "3997:46682": { + "id": "3997:46682", + "type": "INSTANCE", + "fields": { + "parentId": "3997:46681", + "childrenIds": [ + "I3997:46682;68:6257" + ], + "absoluteBoundingBox": { + "height": 55, + "width": 320, + "x": 19283, + "y": 16761 + }, + "absoluteRenderBounds": { + "height": 55, + "width": 320, + "x": 19283, + "y": 16761 + }, + "bottomLeftRadius": 12, + "bottomRightRadius": 12, + "boundVariables": { + "fills": [ + { + "id": "VariableID:1:995", + "type": "VARIABLE_ALIAS" + } + ] + }, + "componentProperties": { + "effect": { + "boundVariables": {}, + "type": "VARIANT", + "value": "default" + } + }, + "constraints": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerRadius": 12, + "counterAxisAlignItems": "CENTER", + "fills": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:995", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.1764705926179886, + "g": 0.1764705926179886, + "r": 0.4588235318660736 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "height": 55, + "inferredAutoLayout": { + "counterAxisAlignItems": "CENTER", + "counterAxisSizingMode": "AUTO", + "itemSpacing": 12, + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutMode": "HORIZONTAL", + "layoutPositioning": "AUTO", + "paddingBottom": 12, + "paddingLeft": 16, + "paddingRight": 16, + "paddingTop": 12, + "primaryAxisAlignItems": "CENTER", + "primaryAxisSizingMode": "FIXED" + }, + "itemSpacing": 12, + "layoutGrow": 0, + "layoutMode": "HORIZONTAL", + "layoutWrap": "NO_WRAP", + "layoutPositioning": "AUTO", + "layoutSizingHorizontal": "FILL", + "layoutSizingVertical": "HUG", + "maxHeight": null, + "maxWidth": null, + "name": "PrimaryButton", + "opacity": 1, + "overflowDirection": "NONE", + "paddingBottom": 12, + "paddingLeft": 16, + "paddingRight": 16, + "paddingTop": 12, + "primaryAxisAlignItems": "CENTER", + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1, + "strokeTopWeight": 1, + "strokeWeight": 1, + "topLeftRadius": 12, + "topRightRadius": 12, + "variantProperties": { + "effect": "default" + }, + "visible": true, + "width": 320, + "x": 0, + "y": 0 + }, + "extra": {}, + "fieldErrors": {} + }, + "3997:46683": { + "id": "3997:46683", + "type": "FRAME", + "fields": { + "parentId": "3997:46681", + "childrenIds": [ + "3997:46684", + "3997:46685" + ], + "absoluteBoundingBox": { + "height": 55, + "width": 320, + "x": 19283, + "y": 16824 + }, + "absoluteRenderBounds": { + "height": 55, + "width": 320, + "x": 19283, + "y": 16824 + }, + "bottomLeftRadius": 12, + "bottomRightRadius": 12, + "boundVariables": { + "fills": [ + { + "id": "VariableID:17:1759", + "type": "VARIABLE_ALIAS" + } + ], + "strokes": [ + { + "id": "VariableID:1:1001", + "type": "VARIABLE_ALIAS" + } + ] + }, + "constraints": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerRadius": 12, + "counterAxisAlignItems": "CENTER", + "fills": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:17:1759", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.9646434783935548, + "g": 0.9646434783935548, + "r": 0.9646434783935548 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "height": 55, + "inferredAutoLayout": { + "counterAxisAlignItems": "CENTER", + "counterAxisSizingMode": "AUTO", + "itemSpacing": 12, + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutMode": "HORIZONTAL", + "layoutPositioning": "AUTO", + "paddingBottom": 12, + "paddingLeft": 16, + "paddingRight": 16, + "paddingTop": 12, + "primaryAxisAlignItems": "SPACE_BETWEEN", + "primaryAxisSizingMode": "FIXED" + }, + "itemSpacing": 12, + "layoutGrow": 0, + "layoutMode": "HORIZONTAL", + "layoutWrap": "NO_WRAP", + "layoutPositioning": "AUTO", + "layoutSizingHorizontal": "FILL", + "layoutSizingVertical": "HUG", + "maxHeight": null, + "maxWidth": null, + "name": "PrimaryButton", + "opacity": 1, + "overflowDirection": "NONE", + "paddingBottom": 12, + "paddingLeft": 16, + "paddingRight": 16, + "paddingTop": 12, + "primaryAxisAlignItems": "SPACE_BETWEEN", + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1, + "strokeTopWeight": 1, + "strokeWeight": 1, + "strokes": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:1001", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.8784313797950745, + "g": 0.8784313797950745, + "r": 0.8784313797950745 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "topLeftRadius": 12, + "topRightRadius": 12, + "visible": true, + "width": 320, + "x": 0, + "y": 63 + }, + "extra": {}, + "fieldErrors": {} + }, + "3997:46684": { + "id": "3997:46684", + "type": "TEXT", + "fields": { + "parentId": "3997:46683", + "absoluteBoundingBox": { + "height": 31, + "width": 116, + "x": 19299, + "y": 16836 + }, + "absoluteRenderBounds": { + "height": 15.908203125, + "width": 113.064453125, + "x": 19300.177734375, + "y": 16843.673828125 + }, + "boundVariables": { + "fills": [ + { + "id": "VariableID:63:1983", + "type": "VARIABLE_ALIAS" + } + ] + }, + "characters": "다른 질문 보내기", + "constraints": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "fills": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:63:1983", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.6634615659713745, + "g": 0.613489031791687, + "r": 0.6184862852096558 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "fontName": { + "family": "Pretendard", + "style": "SemiBold" + }, + "fontSize": 18, + "height": 31, + "layoutGrow": 0, + "layoutPositioning": "AUTO", + "layoutSizingHorizontal": "HUG", + "layoutSizingVertical": "HUG", + "letterSpacing": { + "unit": "PERCENT", + "value": -1 + }, + "lineHeight": { + "unit": "PERCENT", + "value": 170.00000476837158 + }, + "maxHeight": null, + "maxWidth": null, + "name": "다른 질문 보내기", + "opacity": 1, + "strokeAlign": "OUTSIDE", + "strokeWeight": 1, + "textAlignHorizontal": "CENTER", + "textAutoResize": "WIDTH_AND_HEIGHT", + "textStyleId": "S:c5bf8fa1fe5f6bffe79f76cae556417528687add,", + "textTruncation": "DISABLED", + "visible": true, + "width": 116, + "x": 16, + "y": 12, + "styledTextSegments": [ + { + "characters": "다른 질문 보내기", + "end": 9, + "fillStyleId": "", + "fontWeight": 600, + "hyperlink": null, + "indentation": 0, + "listOptions": { + "type": "NONE" + }, + "start": 0, + "textStyleId": "S:c5bf8fa1fe5f6bffe79f76cae556417528687add," + } + ] + }, + "extra": {}, + "fieldErrors": {} + }, + "3997:46685": { + "id": "3997:46685", + "type": "FRAME", + "fields": { + "parentId": "3997:46683", + "childrenIds": [ + "3997:46686", + "3997:46687" + ], + "absoluteBoundingBox": { + "height": 29, + "width": 91, + "x": 19496, + "y": 16837 + }, + "absoluteRenderBounds": { + "height": 29, + "width": 91, + "x": 19496, + "y": 16837 + }, + "bottomLeftRadius": 8, + "bottomRightRadius": 8, + "constraints": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerRadius": 8, + "counterAxisAlignItems": "CENTER", + "effects": [ + { + "blurType": "NORMAL", + "boundVariables": {}, + "radius": 4, + "type": "BACKGROUND_BLUR", + "visible": true + } + ], + "fills": [ + { + "blendMode": "NORMAL", + "boundVariables": {}, + "color": { + "b": 0, + "g": 0, + "r": 0 + }, + "opacity": 0.10000000149011612, + "type": "SOLID", + "visible": true + } + ], + "height": 29, + "inferredAutoLayout": { + "counterAxisAlignItems": "CENTER", + "counterAxisSizingMode": "AUTO", + "itemSpacing": 4, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutMode": "HORIZONTAL", + "layoutPositioning": "AUTO", + "paddingBottom": 4, + "paddingLeft": 10, + "paddingRight": 10, + "paddingTop": 4, + "primaryAxisAlignItems": "MIN", + "primaryAxisSizingMode": "AUTO" + }, + "itemSpacing": 4, + "layoutGrow": 0, + "layoutMode": "HORIZONTAL", + "layoutWrap": "NO_WRAP", + "layoutPositioning": "AUTO", + "layoutSizingHorizontal": "HUG", + "layoutSizingVertical": "HUG", + "maxHeight": null, + "maxWidth": null, + "name": "Frame 1321315504", + "opacity": 1, + "overflowDirection": "NONE", + "paddingBottom": 4, + "paddingLeft": 10, + "paddingRight": 10, + "paddingTop": 4, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1, + "strokeTopWeight": 1, + "strokeWeight": 1, + "topLeftRadius": 8, + "topRightRadius": 8, + "visible": true, + "width": 91, + "x": 213, + "y": 13 + }, + "extra": {}, + "fieldErrors": {} + }, + "3997:46686": { + "id": "3997:46686", + "type": "TEXT", + "fields": { + "parentId": "3997:46685", + "absoluteBoundingBox": { + "height": 16, + "width": 45, + "x": 19506, + "y": 16843.5 + }, + "absoluteRenderBounds": { + "height": 10.4765625, + "width": 42.6328125, + "x": 19507.41796875, + "y": 16845.97265625 + }, + "boundVariables": { + "fills": [ + { + "id": "VariableID:1:1009", + "type": "VARIABLE_ALIAS" + } + ] + }, + "characters": "남은 횟수", + "constraints": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "fills": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:1009", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.5144230723381042, + "g": 0.49649232625961304, + "r": 0.4905153810977936 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "fontName": { + "family": "Pretendard", + "style": "Regular" + }, + "fontSize": 12, + "height": 16, + "layoutGrow": 0, + "layoutPositioning": "AUTO", + "layoutSizingHorizontal": "HUG", + "layoutSizingVertical": "HUG", + "letterSpacing": { + "unit": "PERCENT", + "value": -1 + }, + "lineHeight": { + "unit": "PERCENT", + "value": 129.99999523162842 + }, + "maxHeight": null, + "maxWidth": null, + "name": "남은 횟수", + "opacity": 1, + "strokeAlign": "OUTSIDE", + "strokeWeight": 1, + "textAlignHorizontal": "CENTER", + "textAutoResize": "WIDTH_AND_HEIGHT", + "textStyleId": "S:22cac1fcac10a9dfaf155c08c9a423970a00b27a,", + "textTruncation": "DISABLED", + "visible": true, + "width": 45, + "x": 10, + "y": 6.5, + "styledTextSegments": [ + { + "characters": "남은 횟수", + "end": 5, + "fillStyleId": "", + "fontWeight": 400, + "hyperlink": null, + "indentation": 0, + "listOptions": { + "type": "NONE" + }, + "start": 0, + "textStyleId": "S:22cac1fcac10a9dfaf155c08c9a423970a00b27a," + } + ] + }, + "extra": {}, + "fieldErrors": {} + }, + "3997:46687": { + "id": "3997:46687", + "type": "FRAME", + "fields": { + "parentId": "3997:46685", + "childrenIds": [ + "3997:46688", + "3997:46689" + ], + "absoluteBoundingBox": { + "height": 21, + "width": 22, + "x": 19555, + "y": 16841 + }, + "absoluteRenderBounds": { + "height": 21, + "width": 22, + "x": 19555, + "y": 16841 + }, + "bottomLeftRadius": 0, + "bottomRightRadius": 0, + "constraints": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "counterAxisAlignItems": "CENTER", + "height": 21, + "inferredAutoLayout": { + "counterAxisAlignItems": "CENTER", + "counterAxisSizingMode": "AUTO", + "itemSpacing": 2, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutMode": "HORIZONTAL", + "layoutPositioning": "AUTO", + "paddingBottom": 0, + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "primaryAxisAlignItems": "MIN", + "primaryAxisSizingMode": "AUTO" + }, + "itemSpacing": 2, + "layoutGrow": 0, + "layoutMode": "HORIZONTAL", + "layoutWrap": "NO_WRAP", + "layoutPositioning": "AUTO", + "layoutSizingHorizontal": "HUG", + "layoutSizingVertical": "HUG", + "maxHeight": null, + "maxWidth": null, + "name": "Frame 1321315509", + "opacity": 1, + "overflowDirection": "NONE", + "paddingBottom": 0, + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1, + "strokeTopWeight": 1, + "strokeWeight": 1, + "topLeftRadius": 0, + "topRightRadius": 0, + "visible": true, + "width": 22, + "x": 59, + "y": 4 + }, + "extra": {}, + "fieldErrors": {} + }, + "3997:46688": { + "id": "3997:46688", + "type": "TEXT", + "fields": { + "parentId": "3997:46687", + "absoluteBoundingBox": { + "height": 21, + "width": 9, + "x": 19555, + "y": 16841 + }, + "absoluteRenderBounds": { + "height": 9.4453125, + "width": 7.05859375, + "x": 19555.970703125, + "y": 16846.681640625 + }, + "boundVariables": { + "fills": [ + { + "id": "VariableID:1:1009", + "type": "VARIABLE_ALIAS" + } + ] + }, + "characters": "0", + "constraints": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "fills": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:1009", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.5144230723381042, + "g": 0.49649232625961304, + "r": 0.4905153810977936 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "fontName": { + "family": "Pretendard", + "style": "SemiBold" + }, + "fontSize": 13, + "height": 21, + "layoutGrow": 0, + "layoutPositioning": "AUTO", + "layoutSizingHorizontal": "HUG", + "layoutSizingVertical": "HUG", + "letterSpacing": { + "unit": "PERCENT", + "value": -1 + }, + "lineHeight": { + "unit": "PERCENT", + "value": 160.0000023841858 + }, + "maxHeight": null, + "maxWidth": null, + "name": "0", + "opacity": 1, + "strokeAlign": "OUTSIDE", + "strokeWeight": 1, + "textAlignHorizontal": "CENTER", + "textAutoResize": "WIDTH_AND_HEIGHT", + "textStyleId": "S:a632094a14e864bc7c278c618f26e3a7654bc7b1,", + "textTruncation": "DISABLED", + "visible": true, + "width": 9, + "x": 0, + "y": 0, + "styledTextSegments": [ + { + "characters": "0", + "end": 1, + "fillStyleId": "", + "fontWeight": 600, + "hyperlink": null, + "indentation": 0, + "listOptions": { + "type": "NONE" + }, + "start": 0, + "textStyleId": "S:a632094a14e864bc7c278c618f26e3a7654bc7b1," + } + ] + }, + "extra": {}, + "fieldErrors": {} + }, + "3997:46689": { + "id": "3997:46689", + "type": "TEXT", + "fields": { + "parentId": "3997:46687", + "absoluteBoundingBox": { + "height": 16, + "width": 11, + "x": 19566, + "y": 16843.5 + }, + "absoluteRenderBounds": { + "height": 10.41796875, + "width": 8.484375, + "x": 19566.794921875, + "y": 16846.03125 + }, + "boundVariables": { + "fills": [ + { + "id": "VariableID:1:1009", + "type": "VARIABLE_ALIAS" + } + ] + }, + "characters": "회", + "constraints": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "fills": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:1009", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.5144230723381042, + "g": 0.49649232625961304, + "r": 0.4905153810977936 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "fontName": { + "family": "Pretendard", + "style": "Regular" + }, + "fontSize": 12, + "height": 16, + "layoutGrow": 0, + "layoutPositioning": "AUTO", + "layoutSizingHorizontal": "HUG", + "layoutSizingVertical": "HUG", + "letterSpacing": { + "unit": "PERCENT", + "value": -1 + }, + "lineHeight": { + "unit": "PERCENT", + "value": 129.99999523162842 + }, + "maxHeight": null, + "maxWidth": null, + "name": "회", + "opacity": 1, + "strokeAlign": "OUTSIDE", + "strokeWeight": 1, + "textAlignHorizontal": "CENTER", + "textAutoResize": "WIDTH_AND_HEIGHT", + "textStyleId": "S:22cac1fcac10a9dfaf155c08c9a423970a00b27a,", + "textTruncation": "DISABLED", + "visible": true, + "width": 11, + "x": 11, + "y": 2.5, + "styledTextSegments": [ + { + "characters": "회", + "end": 1, + "fillStyleId": "", + "fontWeight": 400, + "hyperlink": null, + "indentation": 0, + "listOptions": { + "type": "NONE" + }, + "start": 0, + "textStyleId": "S:22cac1fcac10a9dfaf155c08c9a423970a00b27a," + } + ] + }, + "extra": {}, + "fieldErrors": {} + }, + "I3997:46682;68:6257": { + "id": "I3997:46682;68:6257", + "type": "TEXT", + "fields": { + "parentId": "3997:46682", + "absoluteBoundingBox": { + "height": 31, + "width": 128, + "x": 19379, + "y": 16773 + }, + "absoluteRenderBounds": { + "height": 15.890625, + "width": 124.89453125, + "x": 19379.990234375, + "y": 16780.673828125 + }, + "characters": "기록공간 선물하기", + "constraints": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "fills": [ + { + "blendMode": "NORMAL", + "boundVariables": {}, + "color": { + "b": 1, + "g": 1, + "r": 1 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "fontName": { + "family": "Pretendard", + "style": "SemiBold" + }, + "fontSize": 18, + "height": 31, + "layoutGrow": 0, + "layoutPositioning": "AUTO", + "layoutSizingHorizontal": "HUG", + "layoutSizingVertical": "HUG", + "letterSpacing": { + "unit": "PERCENT", + "value": -1 + }, + "lineHeight": { + "unit": "PERCENT", + "value": 170.00000476837158 + }, + "maxHeight": null, + "maxWidth": null, + "name": "버튼명", + "opacity": 1, + "strokeAlign": "OUTSIDE", + "strokeWeight": 1, + "textAlignHorizontal": "CENTER", + "textAutoResize": "WIDTH_AND_HEIGHT", + "textStyleId": "S:c5bf8fa1fe5f6bffe79f76cae556417528687add,", + "textTruncation": "DISABLED", + "visible": true, + "width": 128, + "x": 96, + "y": 12, + "styledTextSegments": [ + { + "characters": "기록공간 선물하기", + "end": 9, + "fillStyleId": "", + "fontWeight": 600, + "hyperlink": null, + "indentation": 0, + "listOptions": { + "type": "NONE" + }, + "start": 0, + "textStyleId": "S:c5bf8fa1fe5f6bffe79f76cae556417528687add," + } + ] + }, + "extra": {}, + "fieldErrors": {} + } + }, + "diagnostics": [] +} diff --git a/docs/r20/clippy.txt b/docs/r20/clippy.txt new file mode 100644 index 0000000..5a6887c --- /dev/null +++ b/docs/r20/clippy.txt @@ -0,0 +1,242 @@ + Checking cfg-if v1.0.4 + Checking serde_core v1.0.229 + Checking memchr v2.8.3 + Checking windows-link v0.2.1 + Checking itoa v1.0.18 + Checking windows-sys v0.61.2 + Checking serde v1.0.229 + Checking smallvec v1.16.0 + Checking allocator-api2 v0.2.21 + Checking hashbrown v0.17.1 + Checking zmij v1.0.23 + Checking pin-project-lite v0.2.17 + Checking bitflags v2.13.1 + Checking zerofrom v0.1.8 + Checking stable_deref_trait v1.2.1 + Checking bytes v1.12.1 + Checking log v0.4.34 + Checking futures-core v0.3.34 + Checking yoke v0.8.3 + Checking once_cell v1.21.4 + Checking percent-encoding v2.3.2 + Compiling getrandom v0.4.3 + Checking zerovec v0.11.8 + Checking num-traits v0.2.19 + Compiling jobserver v0.1.35 + Checking futures-sink v0.3.34 + Compiling cc v1.4.4 + Checking scopeguard v1.2.0 + Checking lock_api v0.4.14 + Checking parking_lot_core v0.9.12 + Checking parking_lot v0.12.5 + Checking futures-channel v0.3.34 + Compiling cmake v0.1.58 + Checking tinystr v0.8.4 + Checking mio v1.2.2 + Compiling aws-lc-sys v0.45.0 + Checking socket2 v0.6.5 + Checking http v1.5.0 + Checking writeable v0.6.4 + Checking typenum v1.20.1 + Checking litemap v0.8.3 + Checking equivalent v1.0.2 + Checking indexmap v2.14.1 + Checking icu_locale_core v2.3.0 + Checking tokio v1.53.1 + Checking zerotrie v0.2.5 + Checking potential_utf v0.1.6 + Checking tracing-core v0.1.36 + Checking utf8_iter v1.0.4 + Checking futures-io v0.3.34 + Checking simd-adler32 v0.3.10 + Checking futures-task v0.3.34 + Checking slab v0.4.12 + Checking zeroize v1.9.0 + Checking futures-util v0.3.34 + Checking icu_collections v2.3.0 + Checking icu_provider v2.3.1 + Checking serde_json v1.0.151 + Checking http-body v1.1.0 + Checking adler2 v2.0.1 + Checking tracing v0.1.44 + Checking icu_properties_data v2.3.0 + Checking icu_normalizer_data v2.3.0 + Checking icu_normalizer v2.3.0 + Checking icu_properties v2.3.0 + Checking crc32fast v1.5.1 + Checking miniz_oxide v0.9.1 + Checking form_urlencoded v1.2.2 + Checking aho-corasick v1.1.5 + Checking regex-syntax v0.8.11 + Checking tower-service v0.3.3 + Checking regex-automata v0.4.18 + Checking flate2 v1.1.10 + Checking idna_adapter v1.2.2 + Checking libc v0.2.189 + Checking miniz_oxide v0.8.9 + Checking rustls-pki-types v1.15.1 + Checking fdeflate v0.3.7 + Checking ipnet v2.12.1 + Checking untrusted v0.9.0 + Checking rand_core v0.10.1 + Checking pxfm v0.1.30 + Checking try-lock v0.2.5 + Checking want v0.3.1 + Checking moxcms v0.8.1 + Checking png v0.18.1 + Checking generic-array v0.14.7 + Checking idna v1.1.0 + Checking httparse v1.10.1 + Checking sync_wrapper v1.0.2 + Checking tower-layer v0.3.3 + Checking byteorder-lite v0.1.0 + Checking httpdate v1.0.3 + Checking atomic-waker v1.1.2 + Checking bytemuck v1.25.2 + Checking subtle v2.6.1 + Checking base64 v0.22.1 + Checking image v0.25.10 + Checking hyper v1.11.1 + Checking url v2.5.8 + Checking zerocopy v0.8.56 + Checking http-body-util v0.1.5 + Checking getrandom v0.2.17 + Checking rand_core v0.6.4 + Checking ppv-lite86 v0.2.21 + Checking hyper-util v0.1.20 + Checking tower v0.5.3 + Checking crypto-common v0.1.7 + Checking block-buffer v0.10.4 + Checking hybrid-array v0.4.14 + Checking ryu v1.0.23 + Checking serde_urlencoded v0.7.1 + Checking digest v0.10.7 + Checking rand_chacha v0.3.1 + Checking chrono v0.4.45 + Checking serde_path_to_error v0.1.20 + Checking cpufeatures v0.2.17 + Checking cpufeatures v0.3.1 + Checking sha2 v0.10.9 + Checking ref-cast v1.0.27 + Checking thiserror v1.0.69 + Checking rand v0.8.8 + Checking block-buffer v0.12.1 + Checking crypto-common v0.2.2 + Checking tower-http v0.6.11 + Checking regex v1.13.1 + Checking futures-executor v0.3.34 + Checking tokio-util v0.7.19 + Checking keyring-core v1.0.0 + Checking const-oid v0.10.2 + Checking dyn-clone v1.0.20 + Checking byteorder v1.5.0 + Checking mime v0.3.17 + Checking tinyvec_macros v0.1.1 + Checking tinyvec v1.12.0 + Checking axum-core v0.5.6 + Checking windows-native-keyring-store v1.1.0 + Checking schemars v1.2.2 + Checking digest v0.11.3 + Checking thiserror v2.0.20 + Checking futures v0.3.34 + Checking oauth2 v5.0.0 + Compiling rmcp-macros v3.2.0 + Checking chacha20 v0.10.2 + Checking sse-stream v0.2.5 + Checking uuid v1.26.0 + Checking tokio-stream v0.1.19 + Checking base64 v0.23.1 + Checking matchit v0.8.4 + Checking axum v0.8.9 + Checking rand v0.10.2 + Checking sha2 v0.11.0 + Checking keyring v4.2.0 + Checking unicode-normalization v0.1.25 + Checking webbrowser v1.2.4 + Checking quick-xml v0.42.0 + Compiling siphasher v1.0.3 + Compiling phf_shared v0.14.0 + Checking castaway v0.2.4 + Checking rustc-hash v2.1.3 + Checking oxc_data_structures v0.148.0 + Checking static_assertions v1.1.0 + Checking compact_str v0.10.0 + Checking oxc_allocator v0.148.0 + Compiling phf v0.14.0 + Checking oxc_estree v0.148.0 + Compiling phf_generator v0.14.0 + Checking oxc_str v0.148.0 + Compiling oxc_ast_macros v0.148.0 + Checking oxc_span v0.148.0 + Compiling phf_macros v0.14.0 + Checking unicode-linebreak v0.1.5 + Checking cow-utils v0.1.3 + Checking smawk v0.3.3 + Checking unicode-width v0.2.2 + Checking textwrap v0.16.2 + Checking unicode-segmentation v1.13.3 + Checking bytecount v0.6.9 + Checking unicode-id-start v1.4.0 + Checking nonmax v0.5.5 + Checking oxc_index v5.0.0 + Checking oxc_diagnostics v0.148.0 + Checking dragonbox_ecma v0.1.12 + Checking oxc_syntax v0.148.0 + Checking oxc_regular_expression v0.148.0 + Checking oxc_ast v0.148.0 + Checking num-integer v0.1.47 + Checking num-bigint v0.5.1 + Checking oxc_ecmascript v0.148.0 + Checking oxc_parser v0.148.0 + Checking oxc_ast_visit v0.148.0 + Checking fastrand v2.5.0 + Checking tempfile v3.27.0 + Checking anyhow v1.0.104 + Checking winapi-util v0.1.11 + Checking same-file v1.0.6 + Checking bstr v1.13.1 + Checking encode_unicode v1.0.0 + Checking console v0.16.4 + Checking globset v0.4.20 + Checking walkdir v2.5.0 + Checking similar v2.7.0 + Checking diff v0.1.13 + Checking yansi v1.0.1 + Checking pretty_assertions v1.4.1 + Checking insta v1.48.0 + Checking windows_x86_64_msvc v0.52.6 + Checking windows-targets v0.52.6 + Checking windows_x86_64_msvc v0.53.1 + Checking windows-targets v0.53.5 + Checking windows-sys v0.59.0 + Checking windows-sys v0.60.2 + Checking io-lifetimes v2.0.4 + Checking io-lifetimes v3.0.1 + Checking io-extras v0.19.0 + Checking fs-set-times v0.20.3 + Checking winx v0.36.4 + Checking maybe-owned v0.3.4 + Checking ambient-authority v0.0.2 + Checking lazy_static v1.5.0 + Checking sharded-slab v0.1.7 + Checking cap-primitives v4.0.3 + Checking matchers v0.2.0 + Checking tracing-log v0.2.0 + Checking nu-ansi-term v0.50.3 + Checking thread_local v1.1.10 + Compiling devup-mcp v0.4.5 (C:\Users\owjs3\orca\workspaces\devup-mcp\r20-browser-measurement\crates\devup-mcp) + Checking tracing-subscriber v0.3.23 + Checking cap-std v4.0.3 + Checking dunce v1.0.5 + Checking devup-mcp-visual v0.4.5 (C:\Users\owjs3\orca\workspaces\devup-mcp\r20-browser-measurement\crates\devup-mcp-visual) + Compiling aws-lc-rs v1.18.1 + Compiling rustls v0.23.43 + Checking rustls-webpki v0.103.15 + Checking tokio-rustls v0.26.4 + Checking rustls-platform-verifier v0.7.0 + Checking hyper-rustls v0.27.9 + Checking reqwest v0.13.4 + Checking rmcp v3.2.0 + Checking devup-mcp-figma v0.4.5 (C:\Users\owjs3\orca\workspaces\devup-mcp\r20-browser-measurement\crates\devup-mcp-figma) + Checking devup-mcp-devup-ui v0.4.5 (C:\Users\owjs3\orca\workspaces\devup-mcp\r20-browser-measurement\crates\devup-mcp-devup-ui) + Finished `dev` profile [unoptimized + debuginfo] target(s) in 3m 48s diff --git a/docs/r20/fmt.txt b/docs/r20/fmt.txt new file mode 100644 index 0000000..e69de29 diff --git a/docs/r20/inputs.txt b/docs/r20/inputs.txt new file mode 100644 index 0000000..ff07563 --- /dev/null +++ b/docs/r20/inputs.txt @@ -0,0 +1,23 @@ +crates/devup-mcp-devup-ui/tests/fixtures/wquw-151-proofread.json +fixtures/wquw-119-snapshot.json +crates/devup-mcp-devup-ui/tests/fixtures/wquw-151-frames/3879-36144.json +crates/devup-mcp-devup-ui/tests/fixtures/wquw-151-frames/3879-36108.json +crates/devup-mcp-devup-ui/tests/fixtures/wquw-151-frames/3879-36059.json +crates/devup-mcp-devup-ui/tests/fixtures/wquw-151-frames/3879-35973.json +crates/devup-mcp-devup-ui/tests/fixtures/wquw-151-frames/3879-35887.json +crates/devup-mcp-devup-ui/tests/fixtures/wquw-151-frames/3879-35729.json +crates/devup-mcp-devup-ui/tests/fixtures/wquw-151-frames/3879-35652.json +crates/devup-mcp-devup-ui/tests/fixtures/wquw-151-frames/3879-35569.json +crates/devup-mcp-devup-ui/tests/fixtures/wquw-151-frames/3879-35518.json +crates/devup-mcp-devup-ui/tests/fixtures/wquw-151-frames/3879-35503.json +crates/devup-mcp-devup-ui/tests/fixtures/r6-completion.json +crates/devup-mcp-devup-ui/tests/fixtures/r17-loading.json +crates/devup-mcp-devup-ui/tests/fixtures/loading-boolean-logos.json +fixtures/r9/non-rendering-node.json +fixtures/r13/f13-1-snapshot.json +fixtures/r8/modal-snapshot.json +fixtures/r2/wquw-120-payload.json +fixtures/r2/wquw-119-payload.json +fixtures/r2/wquw-118-payload.json +fixtures/r14/asset-snapshot.json +docs/r20/asset-full-snapshot.json diff --git a/docs/r20/inventory-build.txt b/docs/r20/inventory-build.txt new file mode 100644 index 0000000..81fa3af --- /dev/null +++ b/docs/r20/inventory-build.txt @@ -0,0 +1,48 @@ + Blocking waiting for file lock on build directory + Compiling windows-sys v0.61.2 + Compiling log v0.4.34 + Compiling dunce v1.0.5 + Compiling aws-lc-sys v0.45.0 + Compiling socket2 v0.6.5 + Compiling mio v1.2.2 + Compiling tokio v1.53.1 + Compiling tracing-core v0.1.36 + Compiling tracing v0.1.44 + Compiling regex-automata v0.4.18 + Compiling hyper v1.11.1 + Compiling hyper-util v0.1.20 + Compiling tower v0.5.3 + Compiling tower-http v0.6.11 + Compiling regex v1.13.1 + Compiling tokio-util v0.7.19 + Compiling keyring-core v1.0.0 + Compiling axum-core v0.5.6 + Compiling windows-native-keyring-store v1.1.0 + Compiling tokio-stream v0.1.19 + Compiling winapi-util v0.1.11 + Compiling axum v0.8.9 + Compiling same-file v1.0.6 + Compiling keyring v4.2.0 + Compiling webbrowser v1.2.4 + Compiling console v0.16.4 + Compiling tempfile v3.27.0 + Compiling globset v0.4.20 + Compiling walkdir v2.5.0 + Compiling insta v1.48.0 + Compiling aws-lc-rs v1.18.1 + Compiling rustls v0.23.43 + Compiling rustls-webpki v0.103.15 + Compiling tokio-rustls v0.26.4 + Compiling hyper-rustls v0.27.9 + Compiling rustls-platform-verifier v0.7.0 + Compiling reqwest v0.13.4 + Compiling rmcp v3.2.0 + Compiling devup-mcp-figma v0.4.5 (C:\Users\owjs3\orca\workspaces\devup-mcp\r20-browser-measurement\crates\devup-mcp-figma) + Compiling devup-mcp-devup-ui v0.4.5 (C:\Users\owjs3\orca\workspaces\devup-mcp\r20-browser-measurement\crates\devup-mcp-devup-ui) +warning: linker stdout: C:\Users\owjs3\orca\workspaces\devup-mcp\r20-browser-measurement\target\debug\examples\r20_inventory.lib 라이브러리 및 C:\Users\owjs3\orca\workspaces\devup-mcp\r20-browser-measurement\target\debug\examples\r20_inventory.exp 개체를 생성하고 있습니다. + | + = note: `#[warn(linker_messages)]` on by default + +warning: `devup-mcp-devup-ui` (example "r20_inventory") generated 1 warning + Finished `dev` profile [unoptimized + debuginfo] target(s) in 13m 33s + Running `target\debug\examples\r20_inventory.exe crates/devup-mcp-devup-ui/tests/fixtures\wquw-151-proofread.json fixtures\wquw-119-snapshot.json crates/devup-mcp-devup-ui/tests/fixtures\wquw-151-frames\3879-36144.json crates/devup-mcp-devup-ui/tests/fixtures\wquw-151-frames\3879-36108.json crates/devup-mcp-devup-ui/tests/fixtures\wquw-151-frames\3879-36059.json crates/devup-mcp-devup-ui/tests/fixtures\wquw-151-frames\3879-35973.json crates/devup-mcp-devup-ui/tests/fixtures\wquw-151-frames\3879-35887.json crates/devup-mcp-devup-ui/tests/fixtures\wquw-151-frames\3879-35729.json crates/devup-mcp-devup-ui/tests/fixtures\wquw-151-frames\3879-35652.json crates/devup-mcp-devup-ui/tests/fixtures\wquw-151-frames\3879-35569.json crates/devup-mcp-devup-ui/tests/fixtures\wquw-151-frames\3879-35518.json crates/devup-mcp-devup-ui/tests/fixtures\wquw-151-frames\3879-35503.json crates/devup-mcp-devup-ui/tests/fixtures\r6-completion.json crates/devup-mcp-devup-ui/tests/fixtures\r17-loading.json crates/devup-mcp-devup-ui/tests/fixtures\loading-boolean-logos.json fixtures\r9\non-rendering-node.json fixtures\r13\f13-1-snapshot.json fixtures\r8\modal-snapshot.json fixtures\r2\wquw-120-payload.json fixtures\r2\wquw-119-payload.json fixtures\r2\wquw-118-payload.json fixtures\r14\asset-snapshot.json` diff --git a/docs/r20/inventory.json b/docs/r20/inventory.json new file mode 100644 index 0000000..3bbed66 --- /dev/null +++ b/docs/r20/inventory.json @@ -0,0 +1,14217 @@ +[ + { + "fixture": "crates/devup-mcp-devup-ui/tests/fixtures\\wquw-151-proofread.json", + "root": "3879:35518", + "inlineInstances": false, + "nodes": 144, + "impacts": { + "none": 26, + "approximated": 0, + "lossy": 40, + "failed": 0 + }, + "diagnostics": [] + }, + { + "fixture": "crates/devup-mcp-devup-ui/tests/fixtures\\wquw-151-proofread.json", + "root": "3879:35518", + "inlineInstances": true, + "nodes": 144, + "impacts": { + "none": 40, + "approximated": 0, + "lossy": 1, + "failed": 0 + }, + "diagnostics": [] + }, + { + "fixture": "fixtures\\wquw-119-snapshot.json", + "root": "3997:46315", + "inlineInstances": false, + "nodes": 19, + "impacts": { + "none": 10, + "approximated": 20, + "lossy": 6, + "failed": 0 + }, + "diagnostics": [ + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46315 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46315", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:1000", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:1000", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 1, + "g": 1, + "r": 1 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:1000", + "appliedValue": { + "generatedSource": [ + "\n \n \n \n \n \n 고작가\n \n 님이 당신의 이야기를
듣고 싶어 합니다.\n
\n \n 편하게 답해주시면, 기록공간이 한 편의 이야기로
정리해 홍길동 님께 전달할게요.\n
\n \n \n \n \n To.\n
\n \n 홍길동 님에게\n
\n \n \n 내 어린 시절 가장 기억나는 순간은?\n \n \n \n From.\n \n \n 고작가 보냄\n \n \n \n \n \n \n \n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46316 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46316", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:1000", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:1000", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 1, + "g": 1, + "r": 1 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:1000", + "appliedValue": { + "generatedSource": [ + " \n \n \n \n \n 고작가\n \n 님이 당신의 이야기를
듣고 싶어 합니다.\n \n \n 편하게 답해주시면, 기록공간이 한 편의 이야기로
정리해 홍길동 님께 전달할게요.\n \n
\n \n \n \n To.\n \n \n 홍길동 님에게\n \n \n \n 내 어린 시절 가장 기억나는 순간은?\n \n \n \n From.\n \n \n 고작가 보냄\n \n \n \n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46321 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46321", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:995", + "details": { + "originalValue": { + "$unsupported": "symbol" + }, + "originalResourceId": "VariableID:1:995", + "appliedValue": { + "generatedSource": [ + " \n \n 고작가\n \n 님이 당신의 이야기를
듣고 싶어 합니다.\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46321 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46321", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:1008", + "details": { + "originalValue": { + "$unsupported": "symbol" + }, + "originalResourceId": "VariableID:1:1008", + "appliedValue": { + "generatedSource": [ + " \n \n 고작가\n \n 님이 당신의 이야기를
듣고 싶어 합니다.\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46321 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46321", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:6646d53069fc8c24eed906edaf8aee78d1a1127a,", + "details": { + "originalValue": "S:6646d53069fc8c24eed906edaf8aee78d1a1127a,", + "originalResourceId": "S:6646d53069fc8c24eed906edaf8aee78d1a1127a,", + "appliedValue": { + "generatedSource": [ + " \n \n 고작가\n \n 님이 당신의 이야기를
듣고 싶어 합니다.\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46322 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46322", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:17:1554", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:17:1554", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.4070510864257813, + "g": 0.3920474350452423, + "r": 0.3920474350452423 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:17:1554", + "appliedValue": { + "generatedSource": [ + " \n 편하게 답해주시면, 기록공간이 한 편의 이야기로
정리해 홍길동 님께 전달할게요.\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46322 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46322", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:0e215484a78b7be9bbbfa4c6ada772650e82023b,", + "details": { + "originalValue": "S:0e215484a78b7be9bbbfa4c6ada772650e82023b,", + "originalResourceId": "S:0e215484a78b7be9bbbfa4c6ada772650e82023b,", + "appliedValue": { + "generatedSource": [ + " \n 편하게 답해주시면, 기록공간이 한 편의 이야기로
정리해 홍길동 님께 전달할게요.\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46323 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46323", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:999", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:999", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.9244915843009948, + "g": 0.9529501795768738, + "r": 0.9695512056350708 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:999", + "appliedValue": { + "generatedSource": [ + " \n \n \n To.\n \n \n 홍길동 님에게\n \n \n \n 내 어린 시절 가장 기억나는 순간은?\n \n \n \n From.\n \n \n 고작가 보냄\n \n \n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46325 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46325", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:995", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:995", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.1764705926179886, + "g": 0.1764705926179886, + "r": 0.4588235318660736 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:995", + "appliedValue": { + "generatedSource": [ + " \n To.\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46325 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46325", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:f3ad91d0eab08878b66518201b5de0c0ef4a9cb8,", + "details": { + "originalValue": "S:f3ad91d0eab08878b66518201b5de0c0ef4a9cb8,", + "originalResourceId": "S:f3ad91d0eab08878b66518201b5de0c0ef4a9cb8,", + "appliedValue": { + "generatedSource": [ + " \n To.\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46326 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46326", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:17:1554", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:17:1554", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.4070510864257813, + "g": 0.3920474350452423, + "r": 0.3920474350452423 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:17:1554", + "appliedValue": { + "generatedSource": [ + " \n 홍길동 님에게\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46326 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46326", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:0e215484a78b7be9bbbfa4c6ada772650e82023b,", + "details": { + "originalValue": "S:0e215484a78b7be9bbbfa4c6ada772650e82023b,", + "originalResourceId": "S:0e215484a78b7be9bbbfa4c6ada772650e82023b,", + "appliedValue": { + "generatedSource": [ + " \n 홍길동 님에게\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46327 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46327", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:998", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:998", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.19891290366649628, + "g": 0.19891290366649628, + "r": 0.21474339067935944 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:998", + "appliedValue": { + "generatedSource": [ + " \n 내 어린 시절 가장 기억나는 순간은?\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46327 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46327", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:730d7f9a1f6c9a8970da178c4e1f451fb972fd8a,", + "details": { + "originalValue": "S:730d7f9a1f6c9a8970da178c4e1f451fb972fd8a,", + "originalResourceId": "S:730d7f9a1f6c9a8970da178c4e1f451fb972fd8a,", + "appliedValue": { + "generatedSource": [ + " \n 내 어린 시절 가장 기억나는 순간은?\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46329 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46329", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:995", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:995", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.1764705926179886, + "g": 0.1764705926179886, + "r": 0.4588235318660736 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:995", + "appliedValue": { + "generatedSource": [ + " \n From.\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46329 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46329", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:f3ad91d0eab08878b66518201b5de0c0ef4a9cb8,", + "details": { + "originalValue": "S:f3ad91d0eab08878b66518201b5de0c0ef4a9cb8,", + "originalResourceId": "S:f3ad91d0eab08878b66518201b5de0c0ef4a9cb8,", + "appliedValue": { + "generatedSource": [ + " \n From.\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46330 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46330", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:17:1554", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:17:1554", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.4070510864257813, + "g": 0.3920474350452423, + "r": 0.3920474350452423 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:17:1554", + "appliedValue": { + "generatedSource": [ + " \n 고작가 보냄\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46330 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46330", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:0e215484a78b7be9bbbfa4c6ada772650e82023b,", + "details": { + "originalValue": "S:0e215484a78b7be9bbbfa4c6ada772650e82023b,", + "originalResourceId": "S:0e215484a78b7be9bbbfa4c6ada772650e82023b,", + "appliedValue": { + "generatedSource": [ + " \n 고작가 보냄\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46332 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46332", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:995", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:995", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.1764705926179886, + "g": 0.1764705926179886, + "r": 0.4588235318660736 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:995", + "appliedValue": { + "generatedSource": [ + " " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "I3997:46332;68:6257 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "I3997:46332;68:6257", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:c5bf8fa1fe5f6bffe79f76cae556417528687add,", + "details": { + "originalValue": "S:c5bf8fa1fe5f6bffe79f76cae556417528687add,", + "originalResourceId": "S:c5bf8fa1fe5f6bffe79f76cae556417528687add,", + "appliedValue": { + "generatedSource": [], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + } + ] + }, + { + "fixture": "fixtures\\wquw-119-snapshot.json", + "root": "3997:46315", + "inlineInstances": true, + "nodes": 19, + "impacts": { + "none": 11, + "approximated": 20, + "lossy": 0, + "failed": 0 + }, + "diagnostics": [ + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46315 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46315", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:1000", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:1000", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 1, + "g": 1, + "r": 1 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:1000", + "appliedValue": { + "generatedSource": [ + "\n \n \n \n \n \n 고작가\n \n 님이 당신의 이야기를
듣고 싶어 합니다.\n \n \n 편하게 답해주시면, 기록공간이 한 편의 이야기로
정리해 홍길동 님께 전달할게요.\n \n
\n \n \n \n To.\n \n \n 홍길동 님에게\n \n \n \n 내 어린 시절 가장 기억나는 순간은?\n \n \n \n From.\n \n \n 고작가 보냄\n \n \n \n
\n \n \n \n 답변 시작하기\n \n \n \n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46316 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46316", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:1000", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:1000", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 1, + "g": 1, + "r": 1 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:1000", + "appliedValue": { + "generatedSource": [ + " \n \n \n \n \n 고작가\n \n 님이 당신의 이야기를
듣고 싶어 합니다.\n \n \n 편하게 답해주시면, 기록공간이 한 편의 이야기로
정리해 홍길동 님께 전달할게요.\n \n
\n \n \n \n To.\n \n \n 홍길동 님에게\n \n \n \n 내 어린 시절 가장 기억나는 순간은?\n \n \n \n From.\n \n \n 고작가 보냄\n \n \n \n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46321 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46321", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:995", + "details": { + "originalValue": { + "$unsupported": "symbol" + }, + "originalResourceId": "VariableID:1:995", + "appliedValue": { + "generatedSource": [ + " \n \n 고작가\n \n 님이 당신의 이야기를
듣고 싶어 합니다.\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46321 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46321", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:1008", + "details": { + "originalValue": { + "$unsupported": "symbol" + }, + "originalResourceId": "VariableID:1:1008", + "appliedValue": { + "generatedSource": [ + " \n \n 고작가\n \n 님이 당신의 이야기를
듣고 싶어 합니다.\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46321 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46321", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:6646d53069fc8c24eed906edaf8aee78d1a1127a,", + "details": { + "originalValue": "S:6646d53069fc8c24eed906edaf8aee78d1a1127a,", + "originalResourceId": "S:6646d53069fc8c24eed906edaf8aee78d1a1127a,", + "appliedValue": { + "generatedSource": [ + " \n \n 고작가\n \n 님이 당신의 이야기를
듣고 싶어 합니다.\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46322 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46322", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:17:1554", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:17:1554", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.4070510864257813, + "g": 0.3920474350452423, + "r": 0.3920474350452423 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:17:1554", + "appliedValue": { + "generatedSource": [ + " \n 편하게 답해주시면, 기록공간이 한 편의 이야기로
정리해 홍길동 님께 전달할게요.\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46322 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46322", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:0e215484a78b7be9bbbfa4c6ada772650e82023b,", + "details": { + "originalValue": "S:0e215484a78b7be9bbbfa4c6ada772650e82023b,", + "originalResourceId": "S:0e215484a78b7be9bbbfa4c6ada772650e82023b,", + "appliedValue": { + "generatedSource": [ + " \n 편하게 답해주시면, 기록공간이 한 편의 이야기로
정리해 홍길동 님께 전달할게요.\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46323 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46323", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:999", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:999", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.9244915843009948, + "g": 0.9529501795768738, + "r": 0.9695512056350708 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:999", + "appliedValue": { + "generatedSource": [ + " \n \n \n To.\n \n \n 홍길동 님에게\n \n \n \n 내 어린 시절 가장 기억나는 순간은?\n \n \n \n From.\n \n \n 고작가 보냄\n \n \n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46325 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46325", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:995", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:995", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.1764705926179886, + "g": 0.1764705926179886, + "r": 0.4588235318660736 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:995", + "appliedValue": { + "generatedSource": [ + " \n To.\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46325 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46325", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:f3ad91d0eab08878b66518201b5de0c0ef4a9cb8,", + "details": { + "originalValue": "S:f3ad91d0eab08878b66518201b5de0c0ef4a9cb8,", + "originalResourceId": "S:f3ad91d0eab08878b66518201b5de0c0ef4a9cb8,", + "appliedValue": { + "generatedSource": [ + " \n To.\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46326 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46326", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:17:1554", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:17:1554", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.4070510864257813, + "g": 0.3920474350452423, + "r": 0.3920474350452423 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:17:1554", + "appliedValue": { + "generatedSource": [ + " \n 홍길동 님에게\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46326 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46326", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:0e215484a78b7be9bbbfa4c6ada772650e82023b,", + "details": { + "originalValue": "S:0e215484a78b7be9bbbfa4c6ada772650e82023b,", + "originalResourceId": "S:0e215484a78b7be9bbbfa4c6ada772650e82023b,", + "appliedValue": { + "generatedSource": [ + " \n 홍길동 님에게\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46327 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46327", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:998", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:998", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.19891290366649628, + "g": 0.19891290366649628, + "r": 0.21474339067935944 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:998", + "appliedValue": { + "generatedSource": [ + " \n 내 어린 시절 가장 기억나는 순간은?\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46327 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46327", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:730d7f9a1f6c9a8970da178c4e1f451fb972fd8a,", + "details": { + "originalValue": "S:730d7f9a1f6c9a8970da178c4e1f451fb972fd8a,", + "originalResourceId": "S:730d7f9a1f6c9a8970da178c4e1f451fb972fd8a,", + "appliedValue": { + "generatedSource": [ + " \n 내 어린 시절 가장 기억나는 순간은?\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46329 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46329", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:995", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:995", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.1764705926179886, + "g": 0.1764705926179886, + "r": 0.4588235318660736 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:995", + "appliedValue": { + "generatedSource": [ + " \n From.\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46329 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46329", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:f3ad91d0eab08878b66518201b5de0c0ef4a9cb8,", + "details": { + "originalValue": "S:f3ad91d0eab08878b66518201b5de0c0ef4a9cb8,", + "originalResourceId": "S:f3ad91d0eab08878b66518201b5de0c0ef4a9cb8,", + "appliedValue": { + "generatedSource": [ + " \n From.\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46330 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46330", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:17:1554", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:17:1554", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.4070510864257813, + "g": 0.3920474350452423, + "r": 0.3920474350452423 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:17:1554", + "appliedValue": { + "generatedSource": [ + " \n 고작가 보냄\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46330 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46330", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:0e215484a78b7be9bbbfa4c6ada772650e82023b,", + "details": { + "originalValue": "S:0e215484a78b7be9bbbfa4c6ada772650e82023b,", + "originalResourceId": "S:0e215484a78b7be9bbbfa4c6ada772650e82023b,", + "appliedValue": { + "generatedSource": [ + " \n 고작가 보냄\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46332 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46332", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:995", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:995", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.1764705926179886, + "g": 0.1764705926179886, + "r": 0.4588235318660736 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:995", + "appliedValue": { + "generatedSource": [ + " \n \n 답변 시작하기\n \n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "I3997:46332;68:6257 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "I3997:46332;68:6257", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:c5bf8fa1fe5f6bffe79f76cae556417528687add,", + "details": { + "originalValue": "S:c5bf8fa1fe5f6bffe79f76cae556417528687add,", + "originalResourceId": "S:c5bf8fa1fe5f6bffe79f76cae556417528687add,", + "appliedValue": { + "generatedSource": [ + " \n 답변 시작하기\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + } + ] + }, + { + "fixture": "crates/devup-mcp-devup-ui/tests/fixtures\\wquw-151-frames\\3879-36144.json", + "root": "3879:36144", + "inlineInstances": false, + "nodes": 128, + "impacts": { + "none": 33, + "approximated": 0, + "lossy": 40, + "failed": 0 + }, + "diagnostics": [] + }, + { + "fixture": "crates/devup-mcp-devup-ui/tests/fixtures\\wquw-151-frames\\3879-36144.json", + "root": "3879:36144", + "inlineInstances": true, + "nodes": 128, + "impacts": { + "none": 47, + "approximated": 0, + "lossy": 1, + "failed": 0 + }, + "diagnostics": [] + }, + { + "fixture": "crates/devup-mcp-devup-ui/tests/fixtures\\wquw-151-frames\\3879-36108.json", + "root": "3879:36108", + "inlineInstances": false, + "nodes": 44, + "impacts": { + "none": 16, + "approximated": 0, + "lossy": 16, + "failed": 0 + }, + "diagnostics": [] + }, + { + "fixture": "crates/devup-mcp-devup-ui/tests/fixtures\\wquw-151-frames\\3879-36108.json", + "root": "3879:36108", + "inlineInstances": true, + "nodes": 44, + "impacts": { + "none": 23, + "approximated": 0, + "lossy": 0, + "failed": 0 + }, + "diagnostics": [] + }, + { + "fixture": "crates/devup-mcp-devup-ui/tests/fixtures\\wquw-151-frames\\3879-36059.json", + "root": "3879:36059", + "inlineInstances": false, + "nodes": 64, + "impacts": { + "none": 19, + "approximated": 0, + "lossy": 40, + "failed": 0 + }, + "diagnostics": [] + }, + { + "fixture": "crates/devup-mcp-devup-ui/tests/fixtures\\wquw-151-frames\\3879-36059.json", + "root": "3879:36059", + "inlineInstances": true, + "nodes": 64, + "impacts": { + "none": 35, + "approximated": 0, + "lossy": 2, + "failed": 0 + }, + "diagnostics": [] + }, + { + "fixture": "crates/devup-mcp-devup-ui/tests/fixtures\\wquw-151-frames\\3879-35973.json", + "root": "3879:35973", + "inlineInstances": false, + "nodes": 210, + "impacts": { + "none": 57, + "approximated": 0, + "lossy": 40, + "failed": 0 + }, + "diagnostics": [] + }, + { + "fixture": "crates/devup-mcp-devup-ui/tests/fixtures\\wquw-151-frames\\3879-35973.json", + "root": "3879:35973", + "inlineInstances": true, + "nodes": 210, + "impacts": { + "none": 99, + "approximated": 0, + "lossy": 5, + "failed": 0 + }, + "diagnostics": [] + }, + { + "fixture": "crates/devup-mcp-devup-ui/tests/fixtures\\wquw-151-frames\\3879-35887.json", + "root": "3879:35887", + "inlineInstances": false, + "nodes": 210, + "impacts": { + "none": 57, + "approximated": 0, + "lossy": 40, + "failed": 0 + }, + "diagnostics": [] + }, + { + "fixture": "crates/devup-mcp-devup-ui/tests/fixtures\\wquw-151-frames\\3879-35887.json", + "root": "3879:35887", + "inlineInstances": true, + "nodes": 210, + "impacts": { + "none": 99, + "approximated": 0, + "lossy": 5, + "failed": 0 + }, + "diagnostics": [] + }, + { + "fixture": "crates/devup-mcp-devup-ui/tests/fixtures\\wquw-151-frames\\3879-35729.json", + "root": "3879:35729", + "inlineInstances": false, + "nodes": 181, + "impacts": { + "none": 52, + "approximated": 0, + "lossy": 40, + "failed": 0 + }, + "diagnostics": [] + }, + { + "fixture": "crates/devup-mcp-devup-ui/tests/fixtures\\wquw-151-frames\\3879-35729.json", + "root": "3879:35729", + "inlineInstances": true, + "nodes": 181, + "impacts": { + "none": 77, + "approximated": 0, + "lossy": 1, + "failed": 0 + }, + "diagnostics": [] + }, + { + "fixture": "crates/devup-mcp-devup-ui/tests/fixtures\\wquw-151-frames\\3879-35652.json", + "root": "3879:35652", + "inlineInstances": false, + "nodes": 188, + "impacts": { + "none": 52, + "approximated": 0, + "lossy": 40, + "failed": 0 + }, + "diagnostics": [] + }, + { + "fixture": "crates/devup-mcp-devup-ui/tests/fixtures\\wquw-151-frames\\3879-35652.json", + "root": "3879:35652", + "inlineInstances": true, + "nodes": 188, + "impacts": { + "none": 83, + "approximated": 0, + "lossy": 1, + "failed": 0 + }, + "diagnostics": [] + }, + { + "fixture": "crates/devup-mcp-devup-ui/tests/fixtures\\wquw-151-frames\\3879-35569.json", + "root": "3879:35569", + "inlineInstances": false, + "nodes": 206, + "impacts": { + "none": 54, + "approximated": 0, + "lossy": 40, + "failed": 0 + }, + "diagnostics": [] + }, + { + "fixture": "crates/devup-mcp-devup-ui/tests/fixtures\\wquw-151-frames\\3879-35569.json", + "root": "3879:35569", + "inlineInstances": true, + "nodes": 206, + "impacts": { + "none": 96, + "approximated": 0, + "lossy": 1, + "failed": 0 + }, + "diagnostics": [] + }, + { + "fixture": "crates/devup-mcp-devup-ui/tests/fixtures\\wquw-151-frames\\3879-35518.json", + "root": "3879:35518", + "inlineInstances": false, + "nodes": 144, + "impacts": { + "none": 35, + "approximated": 0, + "lossy": 40, + "failed": 0 + }, + "diagnostics": [] + }, + { + "fixture": "crates/devup-mcp-devup-ui/tests/fixtures\\wquw-151-frames\\3879-35518.json", + "root": "3879:35518", + "inlineInstances": true, + "nodes": 144, + "impacts": { + "none": 49, + "approximated": 0, + "lossy": 1, + "failed": 0 + }, + "diagnostics": [] + }, + { + "fixture": "crates/devup-mcp-devup-ui/tests/fixtures\\wquw-151-frames\\3879-35503.json", + "root": "3879:35503", + "inlineInstances": false, + "nodes": 15, + "impacts": { + "none": 8, + "approximated": 0, + "lossy": 1, + "failed": 0 + }, + "diagnostics": [] + }, + { + "fixture": "crates/devup-mcp-devup-ui/tests/fixtures\\wquw-151-frames\\3879-35503.json", + "root": "3879:35503", + "inlineInstances": true, + "nodes": 15, + "impacts": { + "none": 8, + "approximated": 0, + "lossy": 1, + "failed": 0 + }, + "diagnostics": [] + }, + { + "fixture": "crates/devup-mcp-devup-ui/tests/fixtures\\r6-completion.json", + "root": "3997:46333", + "inlineInstances": false, + "nodes": 21, + "impacts": { + "none": 9, + "approximated": 15, + "lossy": 6, + "failed": 0 + }, + "diagnostics": [ + { + "code": "DEVUP_CODEGEN_LAYOUT_ACCOUNTED_FOR", + "message": "Verified implicit flex sizing accounts for this FILL dimension.", + "nodeId": "3997:46347", + "fidelityImpact": "none", + "property": "width", + "details": { + "classification": "accounted-for", + "originalValue": 320, + "implicitCssVerification": { + "state": "accounted-for", + "parentId": "3997:46334", + "parentLayoutMode": "VERTICAL", + "childSizing": "FILL", + "generatedParent": " \n \n \n \n \n 이야기가 전달되었어요.\n \n \n 이야기가 성공적으로 전달되었어요!
질문을 보낸 분이 확인할 수 있도록
저희가 알림을 보내드릴게요.\n \n
\n \n
\n \n 내 어린 시절 가장 기억나는 순간은?\n \n \n 길동이가 다섯 살 때, 처음으로 혼자 자전거를 탔던 날이 가장 기억에 남아. 몇 번을 넘어져도 다시 일어나던 모습이 참 대견했단다.\n \n
\n \n \n \n \n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46334 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46334", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:1000", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:1000", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 1, + "g": 1, + "r": 1 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:1000", + "appliedValue": { + "generatedSource": [ + " \n \n \n \n 이야기가 전달되었어요.\n \n \n 이야기가 성공적으로 전달되었어요!
질문을 보낸 분이 확인할 수 있도록
저희가 알림을 보내드릴게요.\n \n
\n \n
\n \n 내 어린 시절 가장 기억나는 순간은?\n \n \n 길동이가 다섯 살 때, 처음으로 혼자 자전거를 탔던 날이 가장 기억에 남아. 몇 번을 넘어져도 다시 일어나던 모습이 참 대견했단다.\n \n
\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46335 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46335", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:995", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:995", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.1764705926179886, + "g": 0.1764705926179886, + "r": 0.4588235318660736 + }, + "opacity": 1, + "type": "SOLID", + "visible": false + } + ], + "originalResourceId": "VariableID:1:995", + "appliedValue": { + "generatedSource": [ + " " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46337 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46337", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:995", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:995", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.1764705926179886, + "g": 0.1764705926179886, + "r": 0.4588235318660736 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:995", + "appliedValue": { + "generatedSource": [], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46345 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46345", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:1008", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:1008", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.12460704147815704, + "g": 0.12460704147815704, + "r": 0.1298076957464218 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:1008", + "appliedValue": { + "generatedSource": [ + " \n 이야기가 전달되었어요.\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46345 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46345", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:6646d53069fc8c24eed906edaf8aee78d1a1127a,", + "details": { + "originalValue": "S:6646d53069fc8c24eed906edaf8aee78d1a1127a,", + "originalResourceId": "S:6646d53069fc8c24eed906edaf8aee78d1a1127a,", + "appliedValue": { + "generatedSource": [ + " \n 이야기가 전달되었어요.\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46346 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46346", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:17:1554", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:17:1554", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.4070510864257813, + "g": 0.3920474350452423, + "r": 0.3920474350452423 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:17:1554", + "appliedValue": { + "generatedSource": [ + " \n 이야기가 성공적으로 전달되었어요!
질문을 보낸 분이 확인할 수 있도록
저희가 알림을 보내드릴게요.\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46346 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46346", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:0e215484a78b7be9bbbfa4c6ada772650e82023b,", + "details": { + "originalValue": "S:0e215484a78b7be9bbbfa4c6ada772650e82023b,", + "originalResourceId": "S:0e215484a78b7be9bbbfa4c6ada772650e82023b,", + "appliedValue": { + "generatedSource": [ + " \n 이야기가 성공적으로 전달되었어요!
질문을 보낸 분이 확인할 수 있도록
저희가 알림을 보내드릴게요.\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46347 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46347", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:1001", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:1001", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.8784313797950745, + "g": 0.8784313797950745, + "r": 0.8784313797950745 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:1001", + "appliedValue": { + "generatedSource": [ + " " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46349 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46349", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:995", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:995", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.1764705926179886, + "g": 0.1764705926179886, + "r": 0.4588235318660736 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:995", + "appliedValue": { + "generatedSource": [ + " \n 내 어린 시절 가장 기억나는 순간은?\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46349 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46349", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:c43949a7dcc7bb888aa8c0dee5547d93c83d0c49,", + "details": { + "originalValue": "S:c43949a7dcc7bb888aa8c0dee5547d93c83d0c49,", + "originalResourceId": "S:c43949a7dcc7bb888aa8c0dee5547d93c83d0c49,", + "appliedValue": { + "generatedSource": [ + " \n 내 어린 시절 가장 기억나는 순간은?\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46350 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46350", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:998", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:998", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.19891290366649628, + "g": 0.19891290366649628, + "r": 0.21474339067935944 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:998", + "appliedValue": { + "generatedSource": [ + " \n 길동이가 다섯 살 때, 처음으로 혼자 자전거를 탔던 날이 가장 기억에 남아. 몇 번을 넘어져도 다시 일어나던 모습이 참 대견했단다.\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46350 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46350", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:dbab53f60e8c4def3ceca64d8adce1a57158e692,", + "details": { + "originalValue": "S:dbab53f60e8c4def3ceca64d8adce1a57158e692,", + "originalResourceId": "S:dbab53f60e8c4def3ceca64d8adce1a57158e692,", + "appliedValue": { + "generatedSource": [ + " \n 길동이가 다섯 살 때, 처음으로 혼자 자전거를 탔던 날이 가장 기억에 남아. 몇 번을 넘어져도 다시 일어나던 모습이 참 대견했단다.\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46352 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46352", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:995", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:995", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.1764705926179886, + "g": 0.1764705926179886, + "r": 0.4588235318660736 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:995", + "appliedValue": { + "generatedSource": [ + " " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "I3997:46352;68:6257 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "I3997:46352;68:6257", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:c5bf8fa1fe5f6bffe79f76cae556417528687add,", + "details": { + "originalValue": "S:c5bf8fa1fe5f6bffe79f76cae556417528687add,", + "originalResourceId": "S:c5bf8fa1fe5f6bffe79f76cae556417528687add,", + "appliedValue": { + "generatedSource": [], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + } + ] + }, + { + "fixture": "crates/devup-mcp-devup-ui/tests/fixtures\\r6-completion.json", + "root": "3997:46333", + "inlineInstances": true, + "nodes": 21, + "impacts": { + "none": 10, + "approximated": 15, + "lossy": 0, + "failed": 0 + }, + "diagnostics": [ + { + "code": "DEVUP_CODEGEN_LAYOUT_ACCOUNTED_FOR", + "message": "Verified implicit flex sizing accounts for this FILL dimension.", + "nodeId": "3997:46347", + "fidelityImpact": "none", + "property": "width", + "details": { + "classification": "accounted-for", + "originalValue": 320, + "implicitCssVerification": { + "state": "accounted-for", + "parentId": "3997:46334", + "parentLayoutMode": "VERTICAL", + "childSizing": "FILL", + "generatedParent": " \n \n \n \n \n 이야기가 전달되었어요.\n \n \n 이야기가 성공적으로 전달되었어요!
질문을 보낸 분이 확인할 수 있도록
저희가 알림을 보내드릴게요.\n \n
\n \n
\n \n 내 어린 시절 가장 기억나는 순간은?\n \n \n 길동이가 다섯 살 때, 처음으로 혼자 자전거를 탔던 날이 가장 기억에 남아. 몇 번을 넘어져도 다시 일어나던 모습이 참 대견했단다.\n \n
\n \n \n \n \n 기록공간이 궁금해요\n \n \n \n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46334 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46334", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:1000", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:1000", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 1, + "g": 1, + "r": 1 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:1000", + "appliedValue": { + "generatedSource": [ + " \n \n \n \n 이야기가 전달되었어요.\n \n \n 이야기가 성공적으로 전달되었어요!
질문을 보낸 분이 확인할 수 있도록
저희가 알림을 보내드릴게요.\n \n
\n \n
\n \n 내 어린 시절 가장 기억나는 순간은?\n \n \n 길동이가 다섯 살 때, 처음으로 혼자 자전거를 탔던 날이 가장 기억에 남아. 몇 번을 넘어져도 다시 일어나던 모습이 참 대견했단다.\n \n
\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46335 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46335", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:995", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:995", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.1764705926179886, + "g": 0.1764705926179886, + "r": 0.4588235318660736 + }, + "opacity": 1, + "type": "SOLID", + "visible": false + } + ], + "originalResourceId": "VariableID:1:995", + "appliedValue": { + "generatedSource": [ + " " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46337 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46337", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:995", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:995", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.1764705926179886, + "g": 0.1764705926179886, + "r": 0.4588235318660736 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:995", + "appliedValue": { + "generatedSource": [], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46345 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46345", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:1008", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:1008", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.12460704147815704, + "g": 0.12460704147815704, + "r": 0.1298076957464218 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:1008", + "appliedValue": { + "generatedSource": [ + " \n 이야기가 전달되었어요.\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46345 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46345", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:6646d53069fc8c24eed906edaf8aee78d1a1127a,", + "details": { + "originalValue": "S:6646d53069fc8c24eed906edaf8aee78d1a1127a,", + "originalResourceId": "S:6646d53069fc8c24eed906edaf8aee78d1a1127a,", + "appliedValue": { + "generatedSource": [ + " \n 이야기가 전달되었어요.\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46346 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46346", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:17:1554", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:17:1554", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.4070510864257813, + "g": 0.3920474350452423, + "r": 0.3920474350452423 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:17:1554", + "appliedValue": { + "generatedSource": [ + " \n 이야기가 성공적으로 전달되었어요!
질문을 보낸 분이 확인할 수 있도록
저희가 알림을 보내드릴게요.\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46346 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46346", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:0e215484a78b7be9bbbfa4c6ada772650e82023b,", + "details": { + "originalValue": "S:0e215484a78b7be9bbbfa4c6ada772650e82023b,", + "originalResourceId": "S:0e215484a78b7be9bbbfa4c6ada772650e82023b,", + "appliedValue": { + "generatedSource": [ + " \n 이야기가 성공적으로 전달되었어요!
질문을 보낸 분이 확인할 수 있도록
저희가 알림을 보내드릴게요.\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46347 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46347", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:1001", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:1001", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.8784313797950745, + "g": 0.8784313797950745, + "r": 0.8784313797950745 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:1001", + "appliedValue": { + "generatedSource": [ + " " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46349 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46349", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:995", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:995", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.1764705926179886, + "g": 0.1764705926179886, + "r": 0.4588235318660736 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:995", + "appliedValue": { + "generatedSource": [ + " \n 내 어린 시절 가장 기억나는 순간은?\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46349 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46349", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:c43949a7dcc7bb888aa8c0dee5547d93c83d0c49,", + "details": { + "originalValue": "S:c43949a7dcc7bb888aa8c0dee5547d93c83d0c49,", + "originalResourceId": "S:c43949a7dcc7bb888aa8c0dee5547d93c83d0c49,", + "appliedValue": { + "generatedSource": [ + " \n 내 어린 시절 가장 기억나는 순간은?\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46350 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46350", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:998", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:998", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.19891290366649628, + "g": 0.19891290366649628, + "r": 0.21474339067935944 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:998", + "appliedValue": { + "generatedSource": [ + " \n 길동이가 다섯 살 때, 처음으로 혼자 자전거를 탔던 날이 가장 기억에 남아. 몇 번을 넘어져도 다시 일어나던 모습이 참 대견했단다.\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46350 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46350", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:dbab53f60e8c4def3ceca64d8adce1a57158e692,", + "details": { + "originalValue": "S:dbab53f60e8c4def3ceca64d8adce1a57158e692,", + "originalResourceId": "S:dbab53f60e8c4def3ceca64d8adce1a57158e692,", + "appliedValue": { + "generatedSource": [ + " \n 길동이가 다섯 살 때, 처음으로 혼자 자전거를 탔던 날이 가장 기억에 남아. 몇 번을 넘어져도 다시 일어나던 모습이 참 대견했단다.\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46352 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46352", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:995", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:995", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.1764705926179886, + "g": 0.1764705926179886, + "r": 0.4588235318660736 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:995", + "appliedValue": { + "generatedSource": [ + " \n \n 기록공간이 궁금해요\n \n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "I3997:46352;68:6257 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "I3997:46352;68:6257", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:c5bf8fa1fe5f6bffe79f76cae556417528687add,", + "details": { + "originalValue": "S:c5bf8fa1fe5f6bffe79f76cae556417528687add,", + "originalResourceId": "S:c5bf8fa1fe5f6bffe79f76cae556417528687add,", + "appliedValue": { + "generatedSource": [ + " \n 기록공간이 궁금해요\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + } + ] + }, + { + "fixture": "crates/devup-mcp-devup-ui/tests/fixtures\\r17-loading.json", + "root": "3831:10708", + "inlineInstances": false, + "nodes": 15, + "impacts": { + "none": 7, + "approximated": 6, + "lossy": 1, + "failed": 0 + }, + "diagnostics": [ + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3831:10708 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3831:10708", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:999", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:999", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.9244915843009948, + "g": 0.9529501795768738, + "r": 0.9695512056350708 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:999", + "appliedValue": { + "generatedSource": [ + "\n \n \n \n 기록해주신 이야기를
정리하고 있어요
잠시만 기다려주세요\n \n \n \n
\n \n 기억을 더듬어 기록하는 시간은
그 자체로 훌륭한 여행이랍니다.\n \n
\n \n \n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3831:10718 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3831:10718", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:998", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:998", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.19891290366649628, + "g": 0.19891290366649628, + "r": 0.21474339067935944 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:998", + "appliedValue": { + "generatedSource": [ + " \n 기록해주신 이야기를
정리하고 있어요
잠시만 기다려주세요\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3831:10718 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3831:10718", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:c5bf8fa1fe5f6bffe79f76cae556417528687add,", + "details": { + "originalValue": "S:c5bf8fa1fe5f6bffe79f76cae556417528687add,", + "originalResourceId": "S:c5bf8fa1fe5f6bffe79f76cae556417528687add,", + "appliedValue": { + "generatedSource": [ + " \n 기록해주신 이야기를
정리하고 있어요
잠시만 기다려주세요\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3831:10720 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3831:10720", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:1843", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:1843", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.84698486328125, + "g": 0.8939971923828125, + "r": 0.917999267578125 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:1843", + "appliedValue": { + "generatedSource": [ + "
\n \n 기억을 더듬어 기록하는 시간은
그 자체로 훌륭한 여행이랍니다.\n \n
" + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3831:10721 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3831:10721", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:998", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:998", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.19891290366649628, + "g": 0.19891290366649628, + "r": 0.21474339067935944 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:998", + "appliedValue": { + "generatedSource": [ + " \n 기억을 더듬어 기록하는 시간은
그 자체로 훌륭한 여행이랍니다.\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3831:10721 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3831:10721", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:a3a810372b741f7e1750b51bdd26f5a491605594,", + "details": { + "originalValue": "S:a3a810372b741f7e1750b51bdd26f5a491605594,", + "originalResourceId": "S:a3a810372b741f7e1750b51bdd26f5a491605594,", + "appliedValue": { + "generatedSource": [ + " \n 기억을 더듬어 기록하는 시간은
그 자체로 훌륭한 여행이랍니다.\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + } + ] + }, + { + "fixture": "crates/devup-mcp-devup-ui/tests/fixtures\\r17-loading.json", + "root": "3831:10708", + "inlineInstances": true, + "nodes": 15, + "impacts": { + "none": 7, + "approximated": 6, + "lossy": 1, + "failed": 0 + }, + "diagnostics": [ + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3831:10708 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3831:10708", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:999", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:999", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.9244915843009948, + "g": 0.9529501795768738, + "r": 0.9695512056350708 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:999", + "appliedValue": { + "generatedSource": [ + "\n \n \n \n 기록해주신 이야기를
정리하고 있어요
잠시만 기다려주세요\n \n \n \n
\n \n 기억을 더듬어 기록하는 시간은
그 자체로 훌륭한 여행이랍니다.\n \n
\n \n \n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3831:10718 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3831:10718", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:998", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:998", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.19891290366649628, + "g": 0.19891290366649628, + "r": 0.21474339067935944 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:998", + "appliedValue": { + "generatedSource": [ + " \n 기록해주신 이야기를
정리하고 있어요
잠시만 기다려주세요\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3831:10718 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3831:10718", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:c5bf8fa1fe5f6bffe79f76cae556417528687add,", + "details": { + "originalValue": "S:c5bf8fa1fe5f6bffe79f76cae556417528687add,", + "originalResourceId": "S:c5bf8fa1fe5f6bffe79f76cae556417528687add,", + "appliedValue": { + "generatedSource": [ + " \n 기록해주신 이야기를
정리하고 있어요
잠시만 기다려주세요\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3831:10720 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3831:10720", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:1843", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:1843", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.84698486328125, + "g": 0.8939971923828125, + "r": 0.917999267578125 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:1843", + "appliedValue": { + "generatedSource": [ + "
\n \n 기억을 더듬어 기록하는 시간은
그 자체로 훌륭한 여행이랍니다.\n \n
" + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3831:10721 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3831:10721", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:998", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:998", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.19891290366649628, + "g": 0.19891290366649628, + "r": 0.21474339067935944 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:998", + "appliedValue": { + "generatedSource": [ + " \n 기억을 더듬어 기록하는 시간은
그 자체로 훌륭한 여행이랍니다.\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3831:10721 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3831:10721", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:a3a810372b741f7e1750b51bdd26f5a491605594,", + "details": { + "originalValue": "S:a3a810372b741f7e1750b51bdd26f5a491605594,", + "originalResourceId": "S:a3a810372b741f7e1750b51bdd26f5a491605594,", + "appliedValue": { + "generatedSource": [ + " \n 기억을 더듬어 기록하는 시간은
그 자체로 훌륭한 여행이랍니다.\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + } + ] + }, + { + "fixture": "crates/devup-mcp-devup-ui/tests/fixtures\\loading-boolean-logos.json", + "root": "3831:10710", + "inlineInstances": false, + "nodes": 4, + "impacts": { + "none": 4, + "approximated": 0, + "lossy": 2, + "failed": 0 + }, + "diagnostics": [] + }, + { + "fixture": "crates/devup-mcp-devup-ui/tests/fixtures\\loading-boolean-logos.json", + "root": "3831:10710", + "inlineInstances": true, + "nodes": 4, + "impacts": { + "none": 4, + "approximated": 0, + "lossy": 2, + "failed": 0 + }, + "diagnostics": [] + }, + { + "fixture": "crates/devup-mcp-devup-ui/tests/fixtures\\loading-boolean-logos.json", + "root": "3831:10725", + "inlineInstances": false, + "nodes": 4, + "impacts": { + "none": 4, + "approximated": 0, + "lossy": 2, + "failed": 0 + }, + "diagnostics": [] + }, + { + "fixture": "crates/devup-mcp-devup-ui/tests/fixtures\\loading-boolean-logos.json", + "root": "3831:10725", + "inlineInstances": true, + "nodes": 4, + "impacts": { + "none": 4, + "approximated": 0, + "lossy": 2, + "failed": 0 + }, + "diagnostics": [] + }, + { + "fixture": "fixtures\\r9\\non-rendering-node.json", + "root": "3997:46703", + "inlineInstances": false, + "nodes": 1, + "impacts": { + "none": 2, + "approximated": 1, + "lossy": 0, + "failed": 0 + }, + "diagnostics": [ + { + "code": "DEVUP_CODEGEN_NON_RENDERING_ASSET", + "message": "Asset paint was omitted, but non-rendering could not be confirmed from collected fields.", + "nodeId": "3997:46703", + "fidelityImpact": "approximated", + "property": "assetReference", + "details": { + "originalValue": { + "visible": true, + "opacity": 1, + "absoluteBoundingBox": { + "height": 24, + "width": 24, + "x": 19389, + "y": 13799.5 + }, + "absoluteRenderBounds": null + }, + "appliedValue": { + "state": "layout-only", + "generatedSource": "", + "sourceTruncated": false + }, + "classification": "unverified-non-rendering", + "reason": "no-render-bounds", + "verification": { + "state": "unverified", + "field": "absoluteRenderBounds", + "fieldPresent": false, + "value": null, + "readError": null + }, + "nextAction": "Recapture visible and absoluteRenderBounds without field errors; an absent field is not evidence of non-rendering." + } + } + ] + }, + { + "fixture": "fixtures\\r9\\non-rendering-node.json", + "root": "3997:46703", + "inlineInstances": true, + "nodes": 1, + "impacts": { + "none": 2, + "approximated": 1, + "lossy": 0, + "failed": 0 + }, + "diagnostics": [ + { + "code": "DEVUP_CODEGEN_NON_RENDERING_ASSET", + "message": "Asset paint was omitted, but non-rendering could not be confirmed from collected fields.", + "nodeId": "3997:46703", + "fidelityImpact": "approximated", + "property": "assetReference", + "details": { + "originalValue": { + "visible": true, + "opacity": 1, + "absoluteBoundingBox": { + "height": 24, + "width": 24, + "x": 19389, + "y": 13799.5 + }, + "absoluteRenderBounds": null + }, + "appliedValue": { + "state": "layout-only", + "generatedSource": "", + "sourceTruncated": false + }, + "classification": "unverified-non-rendering", + "reason": "no-render-bounds", + "verification": { + "state": "unverified", + "field": "absoluteRenderBounds", + "fieldPresent": false, + "value": null, + "readError": null + }, + "nextAction": "Recapture visible and absoluteRenderBounds without field errors; an absent field is not evidence of non-rendering." + } + } + ] + }, + { + "fixture": "fixtures\\r13\\f13-1-snapshot.json", + "root": "3997:46715", + "inlineInstances": false, + "nodes": 51, + "impacts": { + "none": 28, + "approximated": 32, + "lossy": 5, + "failed": 0 + }, + "diagnostics": [ + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46715 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46715", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:17:1548", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:17:1548", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.9586742520332336, + "g": 0.96465665102005, + "r": 0.9695513844490052 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:17:1548", + "appliedValue": { + "generatedSource": [ + "\n \n \n \n \n \n 0\n \n \n /\n \n \n 500자\n \n \n \n \n \n \n \n \n 내 어린 시절 가장 기억나는 순간은?\n \n \n \n \n 이야기가 막힐 때 눌러보세요\n \n \n \n 내 이야기가 이곳에 표시됩니다. (최소 30자)\n \n \n \n 오탈자는 괜찮아요. 맥락을 읽고 다듬어 드려요\n \n \n \n
\n \n 직접 입력\n \n \n
\n
\n \n 녹음하기\n \n \n
\n
\n \n 작성 완료\n \n \n
\n
\n
\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46719 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46719", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:1009", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:1009", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.5144230723381042, + "g": 0.49649232625961304, + "r": 0.4905153810977936 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:1009", + "appliedValue": { + "generatedSource": [], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46723 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46723", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:998", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:998", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.19891290366649628, + "g": 0.19891290366649628, + "r": 0.21474339067935944 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:998", + "appliedValue": { + "generatedSource": [ + " \n 0\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46723 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46723", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:ddba35e8431e5a8140cb2a918793e8682b58ba39,", + "details": { + "originalValue": "S:ddba35e8431e5a8140cb2a918793e8682b58ba39,", + "originalResourceId": "S:ddba35e8431e5a8140cb2a918793e8682b58ba39,", + "appliedValue": { + "generatedSource": [ + " \n 0\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46724 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46724", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:1009", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:1009", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.5144230723381042, + "g": 0.49649232625961304, + "r": 0.4905153810977936 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:1009", + "appliedValue": { + "generatedSource": [ + " \n /\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46724 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46724", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:ddba35e8431e5a8140cb2a918793e8682b58ba39,", + "details": { + "originalValue": "S:ddba35e8431e5a8140cb2a918793e8682b58ba39,", + "originalResourceId": "S:ddba35e8431e5a8140cb2a918793e8682b58ba39,", + "appliedValue": { + "generatedSource": [ + " \n /\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46725 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46725", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:1009", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:1009", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.5144230723381042, + "g": 0.49649232625961304, + "r": 0.4905153810977936 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:1009", + "appliedValue": { + "generatedSource": [ + " \n 500자\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46725 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46725", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:ddba35e8431e5a8140cb2a918793e8682b58ba39,", + "details": { + "originalValue": "S:ddba35e8431e5a8140cb2a918793e8682b58ba39,", + "originalResourceId": "S:ddba35e8431e5a8140cb2a918793e8682b58ba39,", + "appliedValue": { + "generatedSource": [ + " \n 500자\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46726 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46726", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:1001", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:1001", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.8784313797950745, + "g": 0.8784313797950745, + "r": 0.8784313797950745 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:1001", + "appliedValue": { + "generatedSource": [ + " " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46729 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46729", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:998", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:998", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.19891290366649628, + "g": 0.19891290366649628, + "r": 0.21474339067935944 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:998", + "appliedValue": { + "generatedSource": [ + " \n 내 어린 시절 가장 기억나는 순간은?\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46729 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46729", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:6646d53069fc8c24eed906edaf8aee78d1a1127a,", + "details": { + "originalValue": "S:6646d53069fc8c24eed906edaf8aee78d1a1127a,", + "originalResourceId": "S:6646d53069fc8c24eed906edaf8aee78d1a1127a,", + "appliedValue": { + "generatedSource": [ + " \n 내 어린 시절 가장 기억나는 순간은?\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46730 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46730", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:63:934", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:63:934", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.9011186957359314, + "g": 0.9278846383094788, + "r": 0.9024569988250732 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:63:934", + "appliedValue": { + "generatedSource": [ + " \n \n \n 이야기가 막힐 때 눌러보세요\n \n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46733 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46733", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:996", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:996", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.5251548886299133, + "g": 0.5608974099159241, + "r": 0.34247100353240967 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:996", + "appliedValue": { + "generatedSource": [], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46734 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46734", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:996", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:996", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.5251548886299133, + "g": 0.5608974099159241, + "r": 0.34247100353240967 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:996", + "appliedValue": { + "generatedSource": [ + " \n 이야기가 막힐 때 눌러보세요\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46734 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46734", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:750268e778c58f7acf839269cb2e1fb140e113d7,", + "details": { + "originalValue": "S:750268e778c58f7acf839269cb2e1fb140e113d7,", + "originalResourceId": "S:750268e778c58f7acf839269cb2e1fb140e113d7,", + "appliedValue": { + "generatedSource": [ + " \n 이야기가 막힐 때 눌러보세요\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46735 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46735", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:998", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:998", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.19891290366649628, + "g": 0.19891290366649628, + "r": 0.21474339067935944 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:998", + "appliedValue": { + "generatedSource": [ + " \n 내 이야기가 이곳에 표시됩니다. (최소 30자)\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46735 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46735", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:2719cb5b4c133cdf10bfe0bad06eeada1104bab5,", + "details": { + "originalValue": "S:2719cb5b4c133cdf10bfe0bad06eeada1104bab5,", + "originalResourceId": "S:2719cb5b4c133cdf10bfe0bad06eeada1104bab5,", + "appliedValue": { + "generatedSource": [ + " \n 내 이야기가 이곳에 표시됩니다. (최소 30자)\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46737 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46737", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:998", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:998", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.19891290366649628, + "g": 0.19891290366649628, + "r": 0.21474339067935944 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:998", + "appliedValue": { + "generatedSource": [ + " \n 오탈자는 괜찮아요. 맥락을 읽고 다듬어 드려요\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46737 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46737", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:750268e778c58f7acf839269cb2e1fb140e113d7,", + "details": { + "originalValue": "S:750268e778c58f7acf839269cb2e1fb140e113d7,", + "originalResourceId": "S:750268e778c58f7acf839269cb2e1fb140e113d7,", + "appliedValue": { + "generatedSource": [ + " \n 오탈자는 괜찮아요. 맥락을 읽고 다듬어 드려요\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46740 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46740", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:17:1554", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:17:1554", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.4070510864257813, + "g": 0.3920474350452423, + "r": 0.3920474350452423 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:17:1554", + "appliedValue": { + "generatedSource": [ + " \n 직접 입력\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46740 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46740", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:0a76ff5553bb722fb68fd9b379ca5f85f913cadb,", + "details": { + "originalValue": "S:0a76ff5553bb722fb68fd9b379ca5f85f913cadb,", + "originalResourceId": "S:0a76ff5553bb722fb68fd9b379ca5f85f913cadb,", + "appliedValue": { + "generatedSource": [ + " \n 직접 입력\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46742 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46742", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:63:2093", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:63:2093", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.6009615659713745, + "g": 0.6109775304794312, + "r": 0.625 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:63:2093", + "appliedValue": { + "generatedSource": [], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46747 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46747", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:17:1554", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:17:1554", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.4070510864257813, + "g": 0.3920474350452423, + "r": 0.3920474350452423 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:17:1554", + "appliedValue": { + "generatedSource": [ + " \n 녹음하기\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46747 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46747", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:0a76ff5553bb722fb68fd9b379ca5f85f913cadb,", + "details": { + "originalValue": "S:0a76ff5553bb722fb68fd9b379ca5f85f913cadb,", + "originalResourceId": "S:0a76ff5553bb722fb68fd9b379ca5f85f913cadb,", + "appliedValue": { + "generatedSource": [ + " \n 녹음하기\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46749 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46749", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:995", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:995", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.1764705926179886, + "g": 0.1764705926179886, + "r": 0.4588235318660736 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:995", + "appliedValue": { + "generatedSource": [], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46756 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46756", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:17:1554", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:17:1554", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.4070510864257813, + "g": 0.3920474350452423, + "r": 0.3920474350452423 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:17:1554", + "appliedValue": { + "generatedSource": [ + " \n 작성 완료\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46756 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46756", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:0a76ff5553bb722fb68fd9b379ca5f85f913cadb,", + "details": { + "originalValue": "S:0a76ff5553bb722fb68fd9b379ca5f85f913cadb,", + "originalResourceId": "S:0a76ff5553bb722fb68fd9b379ca5f85f913cadb,", + "appliedValue": { + "generatedSource": [ + " \n 작성 완료\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46758 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46758", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:996", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:996", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.5251548886299133, + "g": 0.5608974099159241, + "r": 0.34247100353240967 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:996", + "appliedValue": { + "generatedSource": [], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "I3997:46727;2586:33209 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "I3997:46727;2586:33209", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:17:1554", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:17:1554", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.4070510864257813, + "g": 0.3920474350452423, + "r": 0.3920474350452423 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:17:1554", + "appliedValue": { + "generatedSource": [], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "I3997:46727;2586:33209 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "I3997:46727;2586:33209", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:0a76ff5553bb722fb68fd9b379ca5f85f913cadb,", + "details": { + "originalValue": "S:0a76ff5553bb722fb68fd9b379ca5f85f913cadb,", + "originalResourceId": "S:0a76ff5553bb722fb68fd9b379ca5f85f913cadb,", + "appliedValue": { + "generatedSource": [], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "I3997:46727;2586:33549 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "I3997:46727;2586:33549", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:63:2093", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:63:2093", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.6009615659713745, + "g": 0.6109775304794312, + "r": 0.625 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:63:2093", + "appliedValue": { + "generatedSource": [], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "I3997:46727;2586:33550 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "I3997:46727;2586:33550", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:63:2093", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:63:2093", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.6009615659713745, + "g": 0.6109775304794312, + "r": 0.625 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:63:2093", + "appliedValue": { + "generatedSource": [], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + } + ] + }, + { + "fixture": "fixtures\\r13\\f13-1-snapshot.json", + "root": "3997:46715", + "inlineInstances": true, + "nodes": 51, + "impacts": { + "none": 32, + "approximated": 32, + "lossy": 1, + "failed": 0 + }, + "diagnostics": [ + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46715 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46715", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:17:1548", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:17:1548", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.9586742520332336, + "g": 0.96465665102005, + "r": 0.9695513844490052 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:17:1548", + "appliedValue": { + "generatedSource": [ + "\n \n \n \n \n \n 0\n \n \n /\n \n \n 500자\n \n \n \n \n \n \n 초기화\n \n \n \n \n \n \n 내 어린 시절 가장 기억나는 순간은?\n \n \n \n \n 이야기가 막힐 때 눌러보세요\n \n \n \n 내 이야기가 이곳에 표시됩니다. (최소 30자)\n \n \n \n 오탈자는 괜찮아요. 맥락을 읽고 다듬어 드려요\n \n \n \n
\n \n 직접 입력\n \n \n
\n
\n \n 녹음하기\n \n \n
\n
\n \n 작성 완료\n \n \n
\n
\n
\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46719 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46719", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:1009", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:1009", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.5144230723381042, + "g": 0.49649232625961304, + "r": 0.4905153810977936 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:1009", + "appliedValue": { + "generatedSource": [], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46723 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46723", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:998", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:998", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.19891290366649628, + "g": 0.19891290366649628, + "r": 0.21474339067935944 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:998", + "appliedValue": { + "generatedSource": [ + " \n 0\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46723 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46723", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:ddba35e8431e5a8140cb2a918793e8682b58ba39,", + "details": { + "originalValue": "S:ddba35e8431e5a8140cb2a918793e8682b58ba39,", + "originalResourceId": "S:ddba35e8431e5a8140cb2a918793e8682b58ba39,", + "appliedValue": { + "generatedSource": [ + " \n 0\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46724 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46724", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:1009", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:1009", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.5144230723381042, + "g": 0.49649232625961304, + "r": 0.4905153810977936 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:1009", + "appliedValue": { + "generatedSource": [ + " \n /\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46724 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46724", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:ddba35e8431e5a8140cb2a918793e8682b58ba39,", + "details": { + "originalValue": "S:ddba35e8431e5a8140cb2a918793e8682b58ba39,", + "originalResourceId": "S:ddba35e8431e5a8140cb2a918793e8682b58ba39,", + "appliedValue": { + "generatedSource": [ + " \n /\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46725 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46725", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:1009", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:1009", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.5144230723381042, + "g": 0.49649232625961304, + "r": 0.4905153810977936 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:1009", + "appliedValue": { + "generatedSource": [ + " \n 500자\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46725 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46725", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:ddba35e8431e5a8140cb2a918793e8682b58ba39,", + "details": { + "originalValue": "S:ddba35e8431e5a8140cb2a918793e8682b58ba39,", + "originalResourceId": "S:ddba35e8431e5a8140cb2a918793e8682b58ba39,", + "appliedValue": { + "generatedSource": [ + " \n 500자\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46726 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46726", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:1001", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:1001", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.8784313797950745, + "g": 0.8784313797950745, + "r": 0.8784313797950745 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:1001", + "appliedValue": { + "generatedSource": [ + " " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46729 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46729", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:998", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:998", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.19891290366649628, + "g": 0.19891290366649628, + "r": 0.21474339067935944 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:998", + "appliedValue": { + "generatedSource": [ + " \n 내 어린 시절 가장 기억나는 순간은?\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46729 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46729", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:6646d53069fc8c24eed906edaf8aee78d1a1127a,", + "details": { + "originalValue": "S:6646d53069fc8c24eed906edaf8aee78d1a1127a,", + "originalResourceId": "S:6646d53069fc8c24eed906edaf8aee78d1a1127a,", + "appliedValue": { + "generatedSource": [ + " \n 내 어린 시절 가장 기억나는 순간은?\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46730 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46730", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:63:934", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:63:934", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.9011186957359314, + "g": 0.9278846383094788, + "r": 0.9024569988250732 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:63:934", + "appliedValue": { + "generatedSource": [ + " \n \n \n 이야기가 막힐 때 눌러보세요\n \n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46733 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46733", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:996", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:996", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.5251548886299133, + "g": 0.5608974099159241, + "r": 0.34247100353240967 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:996", + "appliedValue": { + "generatedSource": [], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46734 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46734", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:996", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:996", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.5251548886299133, + "g": 0.5608974099159241, + "r": 0.34247100353240967 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:996", + "appliedValue": { + "generatedSource": [ + " \n 이야기가 막힐 때 눌러보세요\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46734 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46734", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:750268e778c58f7acf839269cb2e1fb140e113d7,", + "details": { + "originalValue": "S:750268e778c58f7acf839269cb2e1fb140e113d7,", + "originalResourceId": "S:750268e778c58f7acf839269cb2e1fb140e113d7,", + "appliedValue": { + "generatedSource": [ + " \n 이야기가 막힐 때 눌러보세요\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46735 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46735", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:998", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:998", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.19891290366649628, + "g": 0.19891290366649628, + "r": 0.21474339067935944 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:998", + "appliedValue": { + "generatedSource": [ + " \n 내 이야기가 이곳에 표시됩니다. (최소 30자)\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46735 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46735", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:2719cb5b4c133cdf10bfe0bad06eeada1104bab5,", + "details": { + "originalValue": "S:2719cb5b4c133cdf10bfe0bad06eeada1104bab5,", + "originalResourceId": "S:2719cb5b4c133cdf10bfe0bad06eeada1104bab5,", + "appliedValue": { + "generatedSource": [ + " \n 내 이야기가 이곳에 표시됩니다. (최소 30자)\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46737 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46737", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:998", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:998", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.19891290366649628, + "g": 0.19891290366649628, + "r": 0.21474339067935944 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:998", + "appliedValue": { + "generatedSource": [ + " \n 오탈자는 괜찮아요. 맥락을 읽고 다듬어 드려요\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46737 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46737", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:750268e778c58f7acf839269cb2e1fb140e113d7,", + "details": { + "originalValue": "S:750268e778c58f7acf839269cb2e1fb140e113d7,", + "originalResourceId": "S:750268e778c58f7acf839269cb2e1fb140e113d7,", + "appliedValue": { + "generatedSource": [ + " \n 오탈자는 괜찮아요. 맥락을 읽고 다듬어 드려요\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46740 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46740", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:17:1554", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:17:1554", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.4070510864257813, + "g": 0.3920474350452423, + "r": 0.3920474350452423 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:17:1554", + "appliedValue": { + "generatedSource": [ + " \n 직접 입력\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46740 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46740", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:0a76ff5553bb722fb68fd9b379ca5f85f913cadb,", + "details": { + "originalValue": "S:0a76ff5553bb722fb68fd9b379ca5f85f913cadb,", + "originalResourceId": "S:0a76ff5553bb722fb68fd9b379ca5f85f913cadb,", + "appliedValue": { + "generatedSource": [ + " \n 직접 입력\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46742 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46742", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:63:2093", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:63:2093", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.6009615659713745, + "g": 0.6109775304794312, + "r": 0.625 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:63:2093", + "appliedValue": { + "generatedSource": [], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46747 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46747", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:17:1554", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:17:1554", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.4070510864257813, + "g": 0.3920474350452423, + "r": 0.3920474350452423 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:17:1554", + "appliedValue": { + "generatedSource": [ + " \n 녹음하기\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46747 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46747", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:0a76ff5553bb722fb68fd9b379ca5f85f913cadb,", + "details": { + "originalValue": "S:0a76ff5553bb722fb68fd9b379ca5f85f913cadb,", + "originalResourceId": "S:0a76ff5553bb722fb68fd9b379ca5f85f913cadb,", + "appliedValue": { + "generatedSource": [ + " \n 녹음하기\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46749 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46749", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:995", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:995", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.1764705926179886, + "g": 0.1764705926179886, + "r": 0.4588235318660736 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:995", + "appliedValue": { + "generatedSource": [], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46756 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46756", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:17:1554", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:17:1554", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.4070510864257813, + "g": 0.3920474350452423, + "r": 0.3920474350452423 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:17:1554", + "appliedValue": { + "generatedSource": [ + " \n 작성 완료\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46756 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46756", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:0a76ff5553bb722fb68fd9b379ca5f85f913cadb,", + "details": { + "originalValue": "S:0a76ff5553bb722fb68fd9b379ca5f85f913cadb,", + "originalResourceId": "S:0a76ff5553bb722fb68fd9b379ca5f85f913cadb,", + "appliedValue": { + "generatedSource": [ + " \n 작성 완료\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46758 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46758", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:996", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:996", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.5251548886299133, + "g": 0.5608974099159241, + "r": 0.34247100353240967 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:996", + "appliedValue": { + "generatedSource": [], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "I3997:46727;2586:33209 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "I3997:46727;2586:33209", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:17:1554", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:17:1554", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.4070510864257813, + "g": 0.3920474350452423, + "r": 0.3920474350452423 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:17:1554", + "appliedValue": { + "generatedSource": [ + " \n 초기화\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "I3997:46727;2586:33209 binds textStyleId to a textStyle the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "I3997:46727;2586:33209", + "severity": "warning", + "property": "textStyleId", + "resourceKind": "textStyle", + "resourceId": "S:0a76ff5553bb722fb68fd9b379ca5f85f913cadb,", + "details": { + "originalValue": "S:0a76ff5553bb722fb68fd9b379ca5f85f913cadb,", + "originalResourceId": "S:0a76ff5553bb722fb68fd9b379ca5f85f913cadb,", + "appliedValue": { + "generatedSource": [ + " \n 초기화\n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "I3997:46727;2586:33549 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "I3997:46727;2586:33549", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:63:2093", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:63:2093", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.6009615659713745, + "g": 0.6109775304794312, + "r": 0.625 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:63:2093", + "appliedValue": { + "generatedSource": [], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "I3997:46727;2586:33550 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "I3997:46727;2586:33550", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:63:2093", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:63:2093", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.6009615659713745, + "g": 0.6109775304794312, + "r": 0.625 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:63:2093", + "appliedValue": { + "generatedSource": [], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + } + ] + }, + { + "fixture": "fixtures\\r8\\modal-snapshot.json", + "root": "3997:46582", + "inlineInstances": false, + "nodes": 57, + "impacts": { + "none": 25, + "approximated": 57, + "lossy": 40, + "failed": 0 + }, + "diagnostics": [ + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46589 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46589", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:1000", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:1000", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 1, + "g": 1, + "r": 1 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:1000", + "appliedValue": { + "generatedSource": [ + "
" + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46590 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46590", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:17:1548", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:17:1548", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.9586742520332336, + "g": 0.96465665102005, + "r": 0.9695513844490052 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:17:1548", + "appliedValue": { + "generatedSource": [ + " \n \n \n \n \n " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46592 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46592", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:995", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:995", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.1764705926179886, + "g": 0.1764705926179886, + "r": 0.4588235318660736 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:995", + "appliedValue": { + "generatedSource": [ + " " + ], + "fallback": null, + "heightPreservation": null, + "derivedPadding": null + }, + "evidenceLimit": "Generated source and collected geometry are comparison evidence, not measured browser layout or proof of responsive equivalence.", + "stage": "projection" + } + }, + { + "code": "DEVUP_CODEGEN_TOKEN_NAME_UNRESOLVED", + "message": "3997:46594 binds fills to a variable the resource catalog did not name, so the resolved value was written instead of its token. Collect the resource, or treat the value in the generated code as a token that still needs a name.", + "nodeId": "3997:46594", + "severity": "warning", + "property": "fills", + "resourceKind": "variable", + "resourceId": "VariableID:1:999", + "details": { + "originalValue": [ + { + "blendMode": "NORMAL", + "boundVariables": { + "color": { + "id": "VariableID:1:999", + "type": "VARIABLE_ALIAS" + } + }, + "color": { + "b": 0.9244915843009948, + "g": 0.9529501795768738, + "r": 0.9695512056350708 + }, + "opacity": 1, + "type": "SOLID", + "visible": true + } + ], + "originalResourceId": "VariableID:1:999", + "appliedValue": { + "generatedSource": [ + "