Des2WF Generation Result Collection
Overview
The des2wf generation output collection โ one document per des2wf run, holding
the emitted wireframe spec, the score that graded it, the flag count, the run
lineage, and the post-render review once the plugin posts its render pair. The
des2wf worker writes it at the end of the single parse โ assemble invocation
(fenced on (_id, attempt)); des2wf-api reads it for materialization, and the
render-review pass amends the same document in place. It is separate from
design_generation_result because the two edges answer different shapes โ a
wireframe spec + score against a design spec + confidence โ and one collection
holding both would make every reader branch on the edge.
Table Definition
| Logical Name | Physical Name | Column Name | Data Type | Primary Key | Relation | Unique | Nullable | Default Value | Remarks |
|---|---|---|---|---|---|---|---|---|---|
| Des2WF Generation Result | des2wf_generation_result | _id | string | โฏ | wf2des:id | The shared wf2des PG row id (the run identity โ one result doc per run, 1:1 with the row, same value as job_id). The row id is globally unique across BOTH edges, which is what keeps the plugin's single (jobId โ rootNodeId) idempotency index safe by construction. CAS write fence on (_id, attempt) |
|||
| edge | string | des2wf | The tagged-union discriminator โ always des2wf on this collection. Dispatch and readers route on it, NEVER on which optional field happens to be populated: two families whose documents differ only by a populated field cannot be told apart safely |
||||||
| organization_id | number | Tenant owner; every read/write filters it | |||||||
| project_id | number | project:id | Tenancy scope; every read/write filters it | ||||||
| job_id | string | wf2des:id | The producing run id โ the same shared wf2des row id as _id, carried as a field so the document is self-describing when read outside its key |
||||||
| attempt | number | The run attempt โ the write fence (CAS on (_id, attempt)) compares it to reject a superseded write, so an SQS redelivery whose older invocation finishes last cannot publish the loser's spec under the winner's job id |
|||||||
| figma_file_key | string | The Figma file the design frame lives in (Figma verbatim; alphanumeric, no underscore) | |||||||
| source_node_id | string | The DESIGN frame โ the input node the run was asked to wireframe | |||||||
| spec | object | Self-contained {spec_version, edge, source_name, source_file_key?, name?, root}. No style_bindings or parse_confirmed; source geometry is opt-in. |
|||||||
| spec.spec_version | string | 1.0 | The materializer wire-contract version | ||||||
| spec.edge | string | des2wf | Literal edge for naming and materializer behavior | ||||||
| spec.source_name | string | empty string | Original frame name | ||||||
| spec.source_file_key | string | โฏ | Pinned Figma file for source glyph/text lookup; optional for legacy results | ||||||
| spec.name | string | โฏ | null | Explicit canvas name override; otherwise des2wf ยท source_name (spec-version fallback) | |||||
| spec.root | object | The existing five cases: layout_frame / instance / compose / text / unmatched. Layout frames may carry placeholder=image, glyph_source and children; instances carry kit identity, slots and DestylePolicy; text carries literal copy and typography. Shared optional source_layout and text_geometry are specified below. | |||||||
| score | object | ds@1.0 โ an emittability GATE times content preservation, versioned. Computed from the artifacts rather than reported by a model about itself, because this product has no human-correction loop and quality converges machine-side through a ratchet. Only score + score_version reach PostgreSQL; the band stays here, where the ratchet reads it. Shape: { score, score_version, gate, band, terms } |
|||||||
| score.score | number | gate ร weighted sum of the scoring terms, rounded to 4 digits |
|||||||
| score.score_version | string | ds@1.0 | The formula version the score was computed under. Bumped on ANY change to a term, a weight or the gate; nothing compares across versions โ it is traceability | ||||||
| score.gate | number | 0 / 1. 0 on any unmatched node, on any non-zero strings_invented / text_displaced / cross_over_text / boxes_coincident, and on depth beyond flat for the absolute layout only โ an auto layout nests on purpose, so gating its depth would score a run 0 for doing exactly what it was asked. A 0 gate drives the whole score to 0: a wireframe with a hole in it is not a partially good wireframe. strings_lost is deliberately NOT gated โ content preservation already grades it |
|||||||
| score.band | object | {low, high, margin}; margin 0.07 when kit selection or graphic classification sets llm_assisted, otherwise 0.0. The mode alone does not imply determinism. |
|||||||
| score.terms | object[] | [] | [{ name, value, weight }] โ every term kept with its own value so a regression is attributable. content_preservation at weight 1.0: the share of the design's strings that appear in the output verbatim, compared as a MULTISET, so a screen that says "Next" three times must still say it three times. integrity, flatness, ink_covered and boundary_fidelity are reported at weight 0.0 โ visible and attributable, moving nothing until there is evidence for what they should be worth |
||||||
| flag_count | number | 0 | Flagged + unmatched nodes โ "how many cells need review". Keeps its wf2des meaning so the shared backend validator stays a single shape; reaches the wf2des row through the manifest row_effects.wf2des |
||||||
| graphic_classification | object | {} | Per-appearance classification audit; empty for older results. Distinct from human override storage and post-render review | ||||||
| graphic_classification.prompt_version | string | Current classifier prompt: des2wf-graphics-visual-2 | |||||||
| graphic_classification.model | string | Configured classifier model | |||||||
| graphic_classification.status | string | not-needed / fallback / partial / complete; complete may include human overrides, not necessarily a model verdict for every node | |||||||
| graphic_classification.source_render_sha256 | string | โฏ | Source PNG hash, or null without evidence | ||||||
| graphic_classification.candidate_count | number | Number of graphic candidates | |||||||
| graphic_classification.decisions | object[] | [] | node_id, applied action, status and reason; optional evidence_sha256, proposal, rendered_kind, rendered_reason, covered_by. See I/O Definition for the nested shape | ||||||
| graphic_classification.fallback_count | number | โฏ | Absent on no-candidate early return | ||||||
| graphic_classification.simplified_count | number | โฏ | Applied simplify decisions, including decoration; not the number of visible placeholder nodes. Absent on no-candidate early return | ||||||
| render_review | object | โฏ | The post-render review block โ the pass the score cannot do, because the score is computed BEFORE anything is drawn, on structural proxies, and cannot see an overlap, a clipped string or a missing element on the rendered canvas. One vision call over the design frame's PNG beside the built wireframe's PNG. Absent until the plugin posts its render pair; post-terminal by design, so it amends a finished run rather than advancing a phase. Shape: { status, finding_count, summary, findings, prompt_version, model, checked_at } |
||||||
| render_review.status | string | reviewed / skipped. A render the vision model would refuse is a fact about the render, not a failure to retry, and is recorded as skipped with skipped_reason and a NULL finding_count โ so nothing can read "no findings" off a pass that never ran |
|||||||
| render_review.finding_count | number | โฏ | Findings reported; NULL on skipped |
||||||
| render_review.summary | string | One sentence of overall judgement; empty on skipped |
|||||||
| render_review.findings | object[] | [] | [{ kind, severity, location, description }]. kind: overlap / overflow / clipped_text / missing_element / extra_element / other; severity: high / medium / low; description is one sentence on what is wrong on the rendered wireframe |
||||||
| render_review.skipped_reason | string | โฏ | Why the pass did not run; present only on status: "skipped" |
||||||
| render_review.prompt_version | string | The review prompt version | |||||||
| render_review.model | string | The reviewing model id | |||||||
| render_review.checked_at | datetime | When the review ran | |||||||
| render_review_previous | object | โฏ | The review block this document carried before the current one โ a re-review MERGES rather than replacing silently, so the ratchet can compare across runs. Absent until a second review lands; same shape as render_review |
||||||
| lineage | object | Shared lineage block on every doc (source S3 key/hash, processor version, processed time). job_id = the producing RUN id โ the shared wf2des row id. Shape: { source_url, source_hash, processor_version, index_schema_version, processed_at, job_id } |
|||||||
| lineage.source_url | string | The RAW design snapshot S3 key โ the full per-node REST envelope, maps retained | |||||||
| lineage.source_hash | string | sha256 of the design FRAME subtree, computed at capture (the parse-cache key) | |||||||
| lineage.processor_version | string | Producing processor version (e.g. des2wf@0.1) |
|||||||
| lineage.index_schema_version | string | 1.1 | Document schema version for this collection | ||||||
| lineage.processed_at | datetime | Terminal-write timestamp | |||||||
| lineage.job_id | string | wf2des:id | The producing run id |
Source geometry
The five spec cases are unchanged. Optional source_layout carries horizontal/vertical
FIXED/HUG/FILL sizing, AUTO/ABSOLUTE positioning, strokes_in_layout, hidden state and per-axis
min/max dimensions. Optional text-node text_geometry carries font_family, auto_resize, line_height,
line_height_pct, letter_spacing, leading_trim, vertical_align, paragraph_spacing and paragraph_indent.
Legacy results without these fields retain the previous materializer behavior.
A layout frame's glyph_source points to source artwork. Materialization is scoped by
spec.source_file_key and preserves the actual instance's overrides. placeholder=image means
approved simplification, not a blanket rule for every icon. Decoration can intentionally emit no paint.
See I/O Definition for contracts and audit field details.
Relations
_id= the sharedwf2desPostgreSQL row id โ 1:1 with the row (the backend creates the row first, the worker writes the doc). The same value appears asjob_idandlineage.job_id.project_idโproject.id;organization_idโ the tenant owner.{figma_file_key, source_node_id}locate the DESIGN frame the run read.- The wireframe the run emitted is the
wireframedoc under the EDGE-SCOPED_id = {project_id}_{figma_file_key}_{node_id}~des2wfโwf_parsekeeps the unsuffixed id for the same frame, so the two edges cannot overwrite each other. spec.rootinstancenodes name a wireframe-kit VARIANT:component_key/component_node_idcome fromwireframe_component.platform_design_idon this edge carries the design node the atom stands in for, not a registry key.- No relation is enforced inside DocumentDB; relations are logical and validated by application code.
Indexes
- PRIMARY KEY (
_id) โ unique;_idIS the sharedwf2desrow id (no surrogate). - The run commit is a CAS on
(_id, attempt)โ it matchesattempt โค the committing attemptand upserts, so a redelivered older attempt cannot overwrite a newer one (not a DB unique index; enforced by the worker's conditional write). - Review checks organization/project scope on the existing result before image or model work. Its merge does not upsert: unknown results raise rather than creating a result document.
- No secondary indexes are defined; reads are by
_idwithin the tenancy filter.
Notes
- The worker writes generation artifacts, the wireframe output, this result and the manifest before
terminal success. The backend webhook alone applies completion, score/version and flags to PG
from
row_effects.wf2des. - Both
primitivesandkitcan use contextual graphic classification. Only kit adds variant selection; missing kit data falls back to primitives. Uncertain graphics preserve their source shape. Approved nonessential imagery becomes ink; confirmed decoration becomes ornament. - The API defaults to
layout=absolute; the current plugin explicitly sendslayout=auto, retaining source hierarchy, native item spacing, one-child wrappers and sizing. - The plugin names the canvas frame
des2wf ยท {source_name}unlessspec.nameoverrides it. The separateWireframeDoc.namestill useswf ยท {design frame name}. - Generation's optional version-pinned source PNG is not the plugin's post-terminal review pair. Review submission requires matching job ID, scoped write access and a COMPLETED row before upload. The pair remains bound to the original source/project; review failure does not undo generation.
graphic_classificationrecords proposals and final rendered coverage separately. A simplified child can remain visually covered by a preserved parent; read rendered_kind/covered_by, not only the proposal. Humangraphic_override_v1records live indes2wf_verdict, not here.- Read the result in full. Truncating the spec through a generic bounded-document path can silently materialize only part of the wireframe.
- A 1.0 structural/content score is not an icon-accuracy or visual-quality pass. Model stubs and the JSON-only offline corpus cannot establish visual recognition accuracy; inspect real-provider output on the canvas.