Skip to content

Design Generation Result Collection

Overview

The PRIMARY generation output collection โ€” one document per wf2des generation run, holding the pinned inputs, the confirmed parse, the assembled DesignSpec, the validator/confidence records, and the plugin placement + feedback bookkeeping. The wf2des worker writes it across the parse and assemble phases (fenced on (_id, attempt)); wf2des-api reads it for preview, review, and materialization. It is never dropped.

Table Definition

Logical Name Physical Name Column Name Data Type Primary Key Relation Unique Nullable Default Value Remarks
Design Generation Result design_generation_result _id string โ—ฏ wf2des:id The wf2des PG row id (the run identity โ€” one result doc per generation, 1:1 with the wf2des row; CAS write fence on (_id, attempt)). PRIMARY collection, never dropped
organization_id number Tenant owner; every read/write filters it
project_id number project:id Tenancy scope; every read/write filters it
attempt number The run attempt โ€” the write fence (CAS on (_id, attempt)) compares it to reject a superseded write; always 1 today โ€” nothing bumps it
screen_id string โ—ฏ From the generation request (e.g. AC_RGST01); generation rows always carry it
request object Request snapshot echoed from the SQS message. Shape: { screen_id: string, prompt: string \| null, placement_target: string \| null, auto_confirm: boolean }
request.screen_id string Requested screen id
request.prompt string โ—ฏ Optional selection prompt, ranked below memo intent
request.placement_target string โ—ฏ Optional node id echoed for placement
request.auto_confirm boolean false normal / true auto โ†’ parse+assemble in one invocation
inputs object Pinned generation inputs (the FIRST act of the parse invocation; rehydrated fail-closed on any hash mismatch at assemble). components = the exact set selected from, so a generation reproduces WHICH components (not only a registry hash). Shape: { wireframe {figma_file_key, node_id, source_hash}, design_rule {design_rule_id, content_hash}, components [{platform_design_id, content_hash}], llm {model_id, prompt_version, screen_review_model_id, screen_review_reasoning_effort, screen_review_enabled} }
inputs.wireframe object { figma_file_key, node_id, source_hash } โ€” the pinned wireframe identity; source_hash โ‰ก the parse-cache key wf_content_hash and lineage.source_hash
inputs.design_rule object โ—ฏ { design_rule_id, content_hash } โ€” the pinned validator program revision (design_rule doc key)
inputs.components object[] [{ platform_design_id, content_hash }] โ€” flat; the exact registry component set selected from (no registry hash). platform_design_id = the design (type=component) row id / design_component._id
inputs.llm object { model_id, prompt_version, screen_review_model_id, screen_review_reasoning_effort, screen_review_enabled } โ€” the pinned model + prompt version (e.g. mp@0.4) and screen-review configuration; pins matching and review configuration so retries do not change provider/model behavior
parse object The confirmed parse record. The full parse tree lives in the immutable parse.json artifact (S3, artifact_urls.parse) โ€” this block holds only the confirmation + snapshotted memo influences. Shape: { confirmed: boolean, confirmed_by: string \| null, confirmed_at: datetime \| null, rejected: {reason_code, note} \| null, memo_influences: [{memo_node_id, text}] }
parse.confirmed boolean false interactively until the designer confirms
parse.confirmed_by string โ—ฏ Confirming user (user:cognito_sub); null until confirmed
parse.confirmed_at datetime โ—ฏ The SINGLE home for the confirmation timestamp; null until confirmed
parse.rejected object โ—ฏ { reason_code, note } recorded on reject (row status 3), fed to curation. reason_code: wrong_roles / wrong_memos / wrong_sections / other. Null unless rejected
parse.memo_influences object[] [{ memo_node_id, text }] โ€” memo text SNAPSHOTTED so it survives a later wireframe reparse
spec object DesignSpec โ€” the assembled, self-contained spec. root is a SpecNode tree of 5 node types (layout_frame / instance / compose / text / unmatched). Specs over ~1MB spill to an S3 pointer (artifact_urls.spec). Shape: { spec_version, parse_confirmed, style_bindings {<token>: string}, root: SpecNode }
spec.spec_version string Spec schema version
spec.parse_confirmed boolean Mirror of the parse confirmation
spec.style_bindings object { <token>: styleId } โ€” token โ†’ Figma style/variable id, derived FROM project_figma_file.style_captures
spec.root object SpecNode tree root. layout_frame { auto_layout, children }; instance { component_key, component_node_id, component_name, variant_props, text_slots, assets, confidence, flagged, source{kind:registry, component_key}, lineage_wf_node_ids } (the platform_design_id lives here on the instance node, not on spec_nodes_flat); compose { primitives + small components composed under rules; ALWAYS flagged; source{kind:composed}, lineage_wf_node_ids }; text { content, style_token, confidence, flagged, lineage_wf_node_ids }; unmatched { placeholder{role,text,bbox}, confidence, flagged:true, source{kind:none}, lineage_wf_node_ids }
spec_nodes_flat object[] Flattened per-content-node view for tuning / flag queries. Element: { layer_path: string, case: string, component_key: string, wf_role: string, confidence: number, flagged: boolean, lineage_wf_node_ids: [string] }. case: instance / compose / text / unmatched. NO platform_design_id (that stays on spec.root instance nodes). Stays inline even when spec spills
selection object Per-section selection record (deterministic filter + section-parallel LLM choice; no similarity/retrieval). Shape: { sections, candidates_considered, composed_count, unmatched_count, asset_fills, truncated }
selection.sections number Section count
selection.candidates_considered number Candidates considered across sections
selection.composed_count number compose-case node count
selection.unmatched_count number unmatched-case placeholder count
selection.asset_fills number Image slots filled from the pinned asset set
selection.truncated boolean Candidate-set truncation flag
screen_plan object โ—ฏ Grounded whole-screen review plus accepted/rejected proposals retained for replay
spec_hash string โ—ฏ Canonical SHA-256 of the base spec; identity fence for plugin render review
assembly_state_hash string โ—ฏ Hash of the pinned stitch/validation state stored at artifact_urls.assembly
layout_fidelity object โ—ฏ Layout preservation metrics: {frames_total, frames_preserved, wrap_total, wrap_preserved, units_collapsed, lost[]}
validator_report object Rules-validator result (violations auto-fixed where safe, else flagged). status: ok / no_rules โ€” no_rules means no registered rule doc, so the validator is a no-op and every node is flagged rules_unvalidated. Shape: { status, violations: [{rule, layer_path, action, detail}], unfixed_flagged }
validator_report.status string ok / no_rules
validator_report.violations object[] [{ rule, layer_path, action, detail }]; action: auto_fixed / flagged
validator_report.unfixed_flagged number Count of violations left flagged (not auto-fixed)
confidence object Computed confidence only (model self-report is banned). flag_count reaches the wf2des row via the completion webhook. Shape: { min, avg, flag_count, formula_version }
confidence.min number Minimum node confidence
confidence.avg number Average node confidence
confidence.flag_count number Flagged-node count; mirrored to wf2des.flag_count via the manifest row_effects.wf2des
confidence.formula_version string Confidence formula version (e.g. cf@0.2)
placement object Plugin build record. Shape: { design_area, placed_node_id, materialized_at, revision, spec_hash, review_id, materializer_report }. design_area is worker-written; the remainder is plugin-written and fingerprint-fenced
placement.design_area object { x, y, w, h } โ€” the resolved DESIGN-area rect (worker-written)
placement.placed_node_id string โ—ฏ The materialized node id (plugin-written)
placement.materialized_at datetime โ—ฏ Materialization timestamp (plugin-written)
placement.materializer_report object[] โ—ฏ [{ layer_path, event, detail }]; event: name_fallback / ordinal_fallback / build_error / font_fallback / prop_rejected / unmatched / preserved
feedback object โ—ฏ Feedback bookkeeping only โ€” changed_nodes + diff for progress/quality tracking; no learning loop. status is recorded onto wf2des.feedback_status by the backend feedback endpoint. Shape: { status, changed_nodes: [string], diff_url, at, by }
feedback.status string fixed / adopted
feedback.changed_nodes string[] Changed layer paths
feedback.diff_url string S3 key of the feedback diff (โ‰ก artifact_urls.feedback_diff)
feedback.at datetime Feedback timestamp
feedback.by string Feedback author (user:cognito_sub)
llm_usage object What this run cost, from the provider's own report: { calls, requests, input_tokens, output_tokens, cached_input_tokens, stages: [{stage, calls, requests, input_tokens, output_tokens, cached_input_tokens}] } โ€” per stage, costliest first. Written by the ASSEMBLE phase (it owns the expensive calls); a parse-only doc carries the empty default
timings object Run-lifecycle timestamps + per-phase durations. Shape: { created_at, parse_done_at, assembled_at, <phase>_ms } โ€” created_at is the run-start anchor (distinct from lineage.processed_at, the terminal-write time); parse stamps created_at / parse_done_at, assemble stamps assembled_at; <phase>_ms are per-phase latencies (e.g. snapshot_ms, parse_ms, selection_ms, assemble_ms, validate_ms)
artifact_urls object Immutable artifact S3 keys. Shape: { result, assembly, spec, parse, feedback_diff }; assembly stores hash-pinned stitch inputs for bounded rendered-output review
artifact_urls.assembly string โ—ฏ Pinned assembly-state artifact whose canonical hash is assembly_state_hash
artifact_urls.result string โ—ฏ Client-facing result artifact key ({org}/{proj}/wf2des/{id}-{ts}-result.json)
artifact_urls.spec string โ—ฏ Spec spill key, present only when spec > ~1MB
artifact_urls.parse string โ—ฏ Immutable parse.json key โ€” the AUTHORITATIVE parse a run used
artifact_urls.feedback_diff string โ—ฏ Feedback diff key
lineage object Shared lineage block on every doc (source S3 key/hash, processor version, processed time). job_id = the producing RUN id: the wf2des row id for generation runs, the job doc _id for internal runs. Shape: { source_url, source_hash, processor_version, index_schema_version, processed_at, job_id }
lineage.source_url string The source snapshot S3 key
lineage.source_hash string Source content hash (โ‰ก inputs.wireframe.source_hash)
lineage.processor_version string Producing processor version (e.g. wf-parse@1.0)
lineage.index_schema_version number Document schema version for this collection
lineage.processed_at datetime Terminal-write timestamp (distinct from timings.created_at, the run-start anchor)
lineage.job_id string The producing run id

Relations

  • _id = the wf2des PostgreSQL wf2des row id โ€” 1:1 with the row (the row is created first, the doc is written by the run).
  • project_id โ†’ project.id; organization_id โ†’ the tenant owner.
  • inputs.components[].platform_design_id โ†’ the platform design (type=component) row id / design_component._id.
  • inputs.design_rule.design_rule_id โ†’ the design_rule doc business key (with content_hash).
  • inputs.wireframe.{figma_file_key, node_id} locate the wireframe cache doc (composite _id = {project_id}_{figma_file_key}_{node_id}).
  • parse.confirmed_by and feedback.by are Cognito subs (user:cognito_sub), stored by value.
  • No relation is enforced inside DocumentDB; relations are logical and validated by application code.

Indexes

  • PRIMARY KEY (_id) โ€” unique; _id IS the wf2des row id (no surrogate).
  • Write fence is a CAS on (_id, attempt) โ€” a zombie/superseded attempt's write is rejected (not a DB unique index; enforced by the worker's conditional write).
  • No secondary indexes are defined; spec_nodes_flat and confidence.flag_count are the flag/tuning query fields but are scanned within the single-doc-per-run model, not indexed cross-doc.

Notes

  • Written by the generation worker across two phases: parse writes inputs + parse (+ artifact_urls.parse, timings, lineage); assemble writes spec / spec_nodes_flat / selection / validator_report / confidence / placement.design_area (+ artifact_urls.result, spec spill). All writes are fenced on (_id, attempt).
  • Read via wf2des-api for preview, memo review, and materialization; the preview/review surfaces read this doc + the immutable parse.json artifact, NEVER the overwritable wireframe cache doc.
  • The worker NEVER writes PostgreSQL. confidence.flag_count, the completion status, and result refs reach the wf2des row only through the ai-status webhook handler (the sole completion-time PG writer), fed from the S3 result manifest.
  • parse.confirmed_at is the single home for the confirmation timestamp (not duplicated into timings). parse.memo_influences[].text is snapshotted so it survives a later wireframe reparse.
  • placement.placed_node_id / materialized_at / materializer_report and the feedback block are written later by the plugin path via wf2des-api, not by the generation worker.
  • A COMPLETED generation is never reprocessed โ€” a full replace would overwrite primary human-event data with a different nondeterministic spec. A terminal row is final; re-running a wireframe creates a NEW row.
  • spec over ~1MB spills to artifact_urls.spec; spec_nodes_flat and the summary blocks stay inline. This is the only byte limit that applies to the doc.