Skip to content

AI Des2WF — I/O Definition

Contract for apps/des2wf/ in guinness-ai-v2. Des2WF converts one Figma design frame into a wireframe spec and a structure record. Changes to these fields or behaviors also belong in the Test Case Design and the Backend Contract.

Run families

Generation is one-shot: parse chains into assembly in the same invocation, with no confirm checkpoint, awaiting_confirm park or rule-ingestion step. The worker never writes PostgreSQL. A separate post-terminal render-review message can amend the completed result after plugin materialization.

Shared contract primitives

The edge discriminator

Generation messages retain edge=des2wf on the dedicated DES2WF queue. The webhook uses type=des2wf. Neither is inferred from optional-field presence. The shared PostgreSQL table remains wf2des, so manifest effects are keyed row_effects.wf2des for both edges.

Generation message

{
  "edge": "des2wf",
  "job_id": "01J...",
  "attempt": 1,
  "nonce": "...",
  "phase": "parse",
  "organization_id": 1,
  "project_id": 7,
  "figma_file_key": "...",
  "source_node_id": "64:6716",
  "design_snapshot_url": "s3://bucket/path/design.json",
  "design_png_url": "s3://bucket/path/version-matched-source.png",
  "source_hash": "<frame-subtree-sha256>",
  "screen_id": null,
  "mode": "primitives",
  "layout": "auto"
}
Field Contract
edge Required literal des2wf
job_id, attempt, nonce Nonempty shared row ID, attempt ≥ 1, nonempty attempt nonce
phase parse (default) or assemble; the standard flow runs both in one invocation
organization_id, project_id Positive IDs
figma_file_key, source_node_id Input file and design frame identity
design_snapshot_url, source_hash Required S3 snapshot URL and frame-subtree hash
design_png_url Optional S3 URL, default null. Backend-captured, version-matched source evidence; older messages remain valid
screen_id Optional, null in the standard DES2WF flow
mode primitives (default) or kit
layout absolute (API/worker default) or auto; current plugin explicitly sends auto, as above

The two wireframes

mode Output Model use
primitives Neutral primitives, verbatim copy, preserved meaningful graphics Contextual graphic classification when usable source PNG evidence is available
kit The same policy plus accepted wireframe-kit variants Graphic classification plus sampled majority-voted kit selection

Kit selection is per distinct design-component context, not a mapping table baked into code. Missing/unusable kit data or rejected proposals leave the primitive representation. Both modes can use a model; neither promises byte-identical output on repeated runs.

The two layouts

absolute puts drawn rows at their source coordinates under the root without reflow. auto preserves the source's container ownership, including one-child wrappers, native itemSpacing, padding, alignment, baseline and wrapping. It does not drop these wrappers and measure new sibling gaps. Absolute overlays remain outside the flow; per-axis sizing and min/max dimensions travel through source_layout. Both layouts preserve copy.

The snapshot envelope — retain the maps

{ "nodes": { "<id>": { "document": {}, "components": {}, "componentSets": {}, "styles": {} } } }

The stored document is the design frame subtree only. Maps are pruned to references used by that subtree, retaining publish keys and named style identity. sectionNodeId only narrows the backend fetch; an invalid scope falls back to full-file lookup without storing siblings or board annotations. source_hash hashes the frame subtree.

The backend keeps the top-level Figma version from the response that supplied the frame, then best-effort exports the source PNG at that same version with absolute bounds. The requesting user's PAT is used for both capture operations. Missing version, export or upload failure leaves the PNG URL absent rather than substituting a newer, unpinned image. The immutable PNG key contains both source and render hashes; see Stores.

Generation — parse phase

Parse reads the JSON snapshot and deterministically extracts the tree: identity, bounds, literal copy, paint, named style keys, component IDs/variants, native layout, source_layout and text_geometry. Component masters use derive_component_context, not the page-tree extractor, so variant partitions are retained.

Invalid input Error
Source does not resolve to a FRAME invalid_input.not_a_frame
No visible authored descendants invalid_input.empty_frame
Snapshot exceeds configured cap (default 20 MB) invalid_input.snapshot_too_large

The plugin can normalize an accepted frame-like selection before capture; this does not broaden the worker's FRAME contract. There is no design-ness detector. based_on=1 records provenance on output; do not treat that field alone as enforcement by every downstream consumer.

Generation — assemble phase

The current order is optional kit selection → classify_sync → census → apply_kit → record_rendered_policy → emit → score. The census kinds are text, box, region, rule, ink, ornament, instance, glyph; emitted specs still use the existing five node cases.

The graphic classifier receives a screen overview, graphic and containing-control crops, names, variants, ancestor context, bounds and local labels. Candidate detection is structural; name, size or image format does not itself authorize replacement.

Decision Applied output
Direction, action, state, identity, list marker, unknown or uncertain glyph: preserve source artwork
High-confidence simplify, no carried information, role content_image or redundant_artwork ink: placeholder; redundant artwork also requires a real local label_node_id
Same guards, role decoration ornament: no paint, with transparent flow space where required
Explicit human override Scoped preserve → glyph or simplify → ink; node before exact component/variant match

The worker reads only graphic_override_v1 overrides, not legacy cached verdicts. Classification is per appearance and AI decisions are not automatically reused across contexts. Batches contain 6 candidates, with 3 concurrent calls and a 180-second classification budget; all candidates are eligible through recursive interleaving. PNG evidence is limited to 20 MiB downloaded bytes and 32,000,000 decoded pixels, with bounds/aspect validation. Missing or invalid evidence, invalid/incomplete answers, unknown/duplicate IDs, provider failures and timeouts preserve artwork and record fallback reasons.

Kit proposals must pass unreachable, copy_truncated, slot_overflow, imagery_heavy, size_implausible and unknown_atom guards. Drawn rows must remain represented in lineage; intentional decoration suppression is an explicit exception, not arbitrary node deletion.

Text stays verbatim. Source-aware text retains typography and neutral literal color; font fallback or necessary reflow can affect wrapping. Ordinary surfaces become neutral boundaries; rules and selected-state markers can be filled. Preserved glyphs are not forcibly recolored. See Abstraction Architecture for materialization details.

Outputs

Output Contract
Canvas frame Plugin materialization; default des2wf · {source_name}, spec-version fallback for an empty source name; explicit spec.name wins
WireframeDoc DocumentDB wireframe; based_on=1, type=0, memos=[], computed summaries; no generated annotations
Result artifact S3 result.json: spec, score fields and graphic_classification
Result document des2wf_generation_result: run identity/scope, spec, nested score, flag_count, lineage, graphic_classification
Manifest S3 artifact references and row_effects.wf2des
Terminal PG row Updated by backend ai-status handler, not the worker
render_review Optional post-terminal addition to the result document
PG wireframe / structure, component output Deferred; the queryable output is the DocumentDB document

The stored WireframeDoc.name still uses wf · {design frame name}; this is separate from the plugin's corrected canvas naming policy. The output document uses {project_id}_{figma_file_key}_{node_id}~des2wf, leaving WF2Des's unsuffixed document untouched.

Spec additions

Des2wfSpec is {spec_version, edge, source_name, source_file_key?, name?, root}. There are no style_bindings or parse_confirmed fields. source_file_key scopes source glyph and text lookup; a mismatched file must not silently clone an unrelated node with the same ID.

Field Shape
source_layout (optional on source-aware nodes) horizontal / vertical: FIXED, HUG or FILL; positioning: AUTO or ABSOLUTE; strokes_in_layout, hidden; optional min_width, max_width, min_height, max_height
text_geometry (optional on text) font_family, auto_resize (NONE / HEIGHT / WIDTH_AND_HEIGHT / TRUNCATE), line_height, line_height_pct, pixel letter_spacing, leading_trim (NONE / CAP_HEIGHT), vertical_align (TOP / CENTER / BOTTOM), paragraph_spacing, paragraph_indent
glyph_source (on a layout frame) Source node reference for preserving actual artwork; clone actual instances and overrides, not the default master

Fields are opt-in; legacy specs without source geometry retain their existing materializer behavior. Cloning can retain read-only text features such as PALT. Font availability remains a runtime constraint.

Graphic audit

graphic_classification defaults to {} for older result documents. New runs record:

Field Meaning
prompt_version, model Classifier identity; current prompt des2wf-graphics-visual-2
status not-needed, fallback, partial or complete
source_render_sha256 Source PNG hash, or null
candidate_count, decisions Candidate count and per-appearance records
fallback_count, simplified_count Optional aggregate counts; absent on the early no-candidate return

Each decision has node_id, applied action (preserve/simplify), status (fallback/override/classified) and reason. Evidence-backed entries can add evidence_sha256 and a proposal containing node_id, role, action, confidence, carries_information, reason and optional label_node_id.

After kit application, rendered_kind, rendered_reason and covered_by explain the final representation, including covered-by-source / covered. A child proposed for simplification can still be covered by its preserved source parent; proposal counts are not counts of visible placeholder nodes.

Render review

The review message carries edge=des2wf, kind=render_review, job_id, organization_id, project_id, required S3 design_png_url and wireframe_png_url, and optional nonce. Unlike generation's optional source PNG, both review images are required.

The plugin binds captures to the original source and project at generation start and checks the materialized job ID. The backend checks write access, scoped row ownership, matching body jobId (400 on mismatch), and COMPLETED status (409 otherwise) before upload/enqueue. The worker validates result scope before image download, model calls or review writes.

The result is amended with render_review; a prior block moves to render_review_previous. reviewed includes findings; skipped includes a reason and null finding_count, not zero. Exports are bounded for the 8000px review limit. Review failure does not revert a completed generation.

Webhook

POST /v1/webhooks/ai-status, authenticated with X-API-Key, carries {type: "des2wf", job_id, attempt, nonce, status}, plus result_manifest_url on success. The manifest's row_effects.wf2des carries status, result_url, flag_count, score and score_version. Score fields are additive to the shared WF2Des shape.

parse_done reports the parse boundary, succeeded applies completion and result references, and failed applies the typed failure. Effects are attempt-guarded; stale or repeated terminal events must not overwrite a newer result.

Score

ds@1.0 = emittability gate × verbatim content preservation as a multiset. Gate failures are unmatched, strings_invented, text_displaced, cross_over_text, boxes_coincident, and depth beyond 2 for absolute only. strings_lost reduces preservation, not the gate.

integrity, flatness, ink_covered and boundary_fidelity are reported at weight 0. The result document contains {score, score_version, gate, band, terms}; PG receives only the sortable score/version pair. Band margin is 0.07 when llm_assisted is true from kit selection or graphic classification, otherwise 0.0. This is not a mode-based reproducibility guarantee.

A 1.0 structural score does not establish icon accuracy or visual fidelity. The JSON-only offline corpus checks fallback and layout; mocked model tests check guards, not recognition accuracy. Visual assessment needs real-provider runs and inspection of regenerated output.

Idempotency & fencing

  • The backend creates the shared row before enqueue and is the sole completion-time PG writer.
  • Result commits are fenced by job ID and attempt; terminal re-emission short-circuits.
  • The open-generation fence includes project, file, node and edge. A terminal state or cancel frees it; no periodic sweep is implied.
  • Render review amends an existing scoped result without upserting an unknown job.