AI Code2WF — Test Cases
These cases validate the MVP contract in Code2WF I/O Definition. Page build/capture tests belong to Page Import. Every contract area must map to at least one case below; the Coverage Matrix is the traceability index.
Convention: Test IDs use C2W-<area>-<NN>, where the area is trigger (T), queue/dispatch (Q), source (S), conversion (C), idempotency/webhook (I), result API (R), Figma recovery (F), or authorization/security (A). The Expected column is the assertion contract; behavior not stated there is not asserted.
The default suite is local and deterministic. Deployed end-to-end checks are opt-in smoke tests.
| Layer |
Scope |
Tooling |
| Unit (U) |
Closed message/result schemas, one-read source-pin derivation, source/lineage validation, deterministic conversion and annotation numbering, shared DesignSpecModel serialization, limits, and full-artifact validation |
pytest, no network; storage and webhook clients faked at their boundaries |
| Component (C) |
Backend trigger/list/result/placement boundaries, one complete worker record through immutable result + manifest publication, webhook effects, and plugin materialization/recovery |
Existing backend and plugin test runners; ephemeral PostgreSQL where the backend row is exercised; localstack S3/SQS for artifact flow; webhook and Figma boundaries mocked |
| End-to-end (E) |
Deployed non-production backend, queue, worker, S3, PostgreSQL, and authenticated Figma plugin round-trip |
Opt-in smoke suite using dedicated test data and bounded runtime |
Fixtures
Build messages and artifacts from shared fixtures rather than hand-writing partial dictionaries.
| Fixture |
Purpose |
completed_page_import(...) |
Scoped completed Page Import row plus one immutable normalized-manifest object with controllable raw bytes, page_result_hash, and capture_hash |
build_code2wf_message(**overrides) |
Well-formed closed SQS message with Code2WF identity, tenant, fixed attempt, nonce, Page Import pins, and screen_id |
page_result_bytes(**overrides) |
Exact normalized-manifest bytes used for the backend's single verified read and the worker's source validation |
design_spec(**overrides) |
Canonical existing DesignSpecModel tree, including shared defaults and boundary variants |
code2wf_result_artifact(**overrides) |
Complete worker artifact: outer identity/status/time, Page Import inputs, and nested spec |
code2wf_terminal_manifest(**overrides) |
Success/failure manifest with the existing row_effects.code2wf contract |
code2wf_row(status=..., materialized_at=...) |
Scoped backend row in processing/completed/failed and materialized/unmaterialized states |
mock_ai_status(http_status=200) |
Captures the terminal webhook envelope and returns the configured response |
figma_file_fixture(...) |
Current-page target, stale/cross-page targets, prior stamped root, and materializer failure variants |
Coverage Matrix
Rows are contract areas from the I/O Definition. Every defined case ID appears here.
| Contract area |
Happy path |
Failure path |
Idempotency / Recovery |
| Trigger and PostgreSQL row |
C2W-T-01, C2W-T-04 |
C2W-T-02, C2W-T-03, C2W-T-05, C2W-T-06, C2W-T-08 |
C2W-T-04, C2W-T-07 |
| Dispatch message and Page Import pins |
C2W-Q-01, C2W-Q-05 |
C2W-Q-02, C2W-Q-03, C2W-Q-04 |
C2W-Q-02, C2W-Q-05 |
| Worker source validation |
C2W-S-01, C2W-S-07 |
C2W-S-02, C2W-S-03, C2W-S-04, C2W-S-05, C2W-S-06 |
— |
| Conversion and shared spec |
C2W-C-01, C2W-C-02, C2W-C-03, C2W-C-04, C2W-C-06, C2W-C-08, C2W-C-09, C2W-C-13, C2W-C-14 |
C2W-C-05, C2W-C-07, C2W-C-10, C2W-C-11, C2W-C-12, C2W-C-15 |
C2W-C-02, C2W-C-08, C2W-C-13 |
| Immutable result, manifest, and webhook |
C2W-I-04 |
C2W-I-03, C2W-I-05, C2W-I-07 |
C2W-I-01, C2W-I-02, C2W-I-06 |
| Result/list API |
C2W-R-01, C2W-R-05, C2W-R-06, C2W-R-08 |
C2W-R-02, C2W-R-03, C2W-R-04, C2W-R-07 |
— |
| Figma recovery and placement |
C2W-F-01, C2W-F-06, C2W-F-08, C2W-F-09, C2W-F-10, C2W-F-11, C2W-F-12, C2W-F-13, C2W-F-14, C2W-F-16 |
C2W-F-02, C2W-F-03, C2W-F-04, C2W-F-05, C2W-F-07, C2W-F-15, C2W-F-17 |
C2W-F-02, C2W-F-03, C2W-F-08, C2W-F-09, C2W-F-14, C2W-F-15, C2W-F-18 |
| Authorization and security |
— |
C2W-A-01, C2W-A-02, C2W-A-03, C2W-A-04, C2W-A-05 |
— |
1. Trigger and Row Contract
| ID |
Scenario |
Expected |
| C2W-T-01 |
Valid completed Page Import and valid Figma fields |
Generate UUIDv7; insert one code2wf row with status="0", attempt=1; send one SQS message |
| C2W-T-02 |
Page Import is processing/failed |
409; no Code2WF row or message |
| C2W-T-03 |
Page Import is missing, deleted, or in another scope |
404; no row or message |
| C2W-T-04 |
Identical valid trigger body is submitted twice |
Create two backend-generated rows and dispatch two jobs |
| C2W-T-05 |
Request supplies code2wfId |
400; caller-generated job IDs are not accepted |
| C2W-T-06 |
SQS send fails after insert |
CAS processing row to failed using id/attempt/status; safe error is pollable |
| C2W-T-07 |
New trigger after dispatch failure |
Create and dispatch a new row; do not mutate or redispatch the failed row |
| C2W-T-08 |
Request tries status, attempt, result, or materialization fields |
400; server-owned fields are not accepted |
Schema assertion: the row uses the WF2Des-aligned fields only—id, organization/project, page_import_id, figma_file_key, screen_id, optional placement_target, status using the existing wf2des_status enum, fixed attempt, result/error/flag fields, materialized_at, and shared audit fields. It does not persist Page Import hashes, Figma page IDs, nonces, materialization states, node IDs, or retry ledgers.
2. Dispatch Contract
| ID |
Scenario |
Expected |
| C2W-Q-01 |
Backend dispatches a valid job |
Message contains exact Page Import result URL/hash/capture hash resolved from the completed import |
| C2W-Q-02 |
Backend resolves the completed Page Import pins for dispatch |
Read and verify the immutable normalized manifest exactly once; that one read supplies page_result_url, page_result_hash, and capture_hash. Missing or corrupt bytes fail before SQS dispatch; do not assert a PostgreSQL/S3 transaction |
| C2W-Q-03 |
Message attempt is not 1 |
Worker rejects invalid_message |
| C2W-Q-04 |
Message contains Figma destination or credentials |
Closed message validation rejects it |
| C2W-Q-05 |
Valid message nonce is observed |
Validate and log it, but never persist it or include it in row CAS; duplicate delivery reuses the immutable result |
3. Source Validation
| ID |
Scenario |
Expected |
| C2W-S-01 |
Valid source bytes and lineage |
Conversion proceeds |
| C2W-S-02 |
Result hash differs |
Terminal source_hash_mismatch; no output |
| C2W-S-03 |
Organization/project/Page Import ID differs |
Terminal source_scope_mismatch |
| C2W-S-04 |
Capture hash differs |
Terminal source_scope_mismatch |
| C2W-S-05 |
Source/object escapes tenant/import prefix |
Terminal source_scope_mismatch |
| C2W-S-06 |
Unsupported Page Import schema |
Terminal unsupported_source_schema |
| C2W-S-07 |
Original route is unavailable |
No effect; worker reads only immutable Page Import artifacts |
4. Conversion and Schema
| ID |
Scenario |
Expected |
| C2W-C-01 |
Grouping, text, controls, and geometry are present |
Exact existing DesignSpecModel with layout_frame / text nodes and unique layer_path values |
| C2W-C-02 |
Captured link/form/control evidence exists |
Stable sibling marker plus matching deterministic annotation text; the original control label is unchanged |
| C2W-C-03 |
No evidence exists for an assumed interaction |
No invented behavior annotation |
| C2W-C-04 |
Button, input, or other ordinary control is mapped |
Existing nested layout_frame / text; no new primitive node case |
| C2W-C-05 |
Media, overlap, transform, or positioning relationship cannot be expressed by existing nodes |
Existing visible unmatched placeholder with flagged=true and source.kind="none" |
| C2W-C-06 |
Valid final compatibility fields |
spec_version="1.0", parse_confirmed=true, style_bindings={}, and an existing SpecNode root |
| C2W-C-07 |
Unknown node discriminator |
Shared discriminated-union validation returns invalid_result; nothing is published |
| C2W-C-08 |
Multiple evidence-backed annotations |
[A001] markers are assigned deterministically in normalized DOM order |
| C2W-C-09 |
Spec has flagged/unmatched outcomes |
flag_count equals the count of existing spec outcomes with flagged=true |
| C2W-C-10 |
Result exceeds a locked structural limit |
Terminal result_limit_exceeded |
| C2W-C-11 |
UTF-8 result exceeds 10 MiB |
Terminal result_limit_exceeded |
| C2W-C-12 |
Code2WF producer attempts a Code2WF-only spec field/collection |
Producer contract test fails; only fields from the existing shared model are emitted |
| C2W-C-13 |
Valid spec is serialized |
Exact DesignSpecModel.model_dump(mode="json") output includes shared defaults such as lineage arrays, text style refs, nullable source component key, and all auto-layout defaults |
| C2W-C-14 |
Page Import document is taller than its viewport |
Screen bbox.h uses full document_height; below-the-fold visible evidence is represented |
| C2W-C-15 |
Source has absolute/fixed/sticky overlap that auto-layout cannot preserve |
Do not add an absolute-position field; preserve visible order where possible and emit a flagged unmatched placeholder for irreducible content |
Property tests generate the existing node union at boundary values and assert maximum depth/node counts, finite bounding boxes, unique paths/markers, exact DesignSpecModel validation/serialization, unknown-discriminator rejection, and an emitter allowlist matching the existing shared fields. A regression test also records the current shared-model behavior that extra object properties are ignored rather than falsely asserting that Pydantic rejects them.
5. Result Idempotency and Webhook
| ID |
Scenario |
Expected |
| C2W-I-01 |
Same SQS record delivered twice |
One immutable result/manifest pair; both deliveries converge on the manifest URL |
| C2W-I-02 |
Concurrent worker loses conditional write |
Read and validate winner; emit winner's terminal event |
| C2W-I-03 |
Existing result has different lineage |
Fail closed; never overwrite |
| C2W-I-04 |
Valid success webhook on processing row |
Validate result_manifest_url; CAS (id, attempt=1, status="0") to completed; store inner row_effects.code2wf.result_url and flag count |
| C2W-I-05 |
Valid failure webhook on processing row |
Same CAS to failed; require the failure manifest and safe error, store its failed-artifact result_url / error_message, and leave row flag_count null |
| C2W-I-06 |
Duplicate/conflicting webhook after terminal state |
Accepted no-op; terminal winner is unchanged |
| C2W-I-07 |
Webhook dependency temporarily unavailable |
SQS record retries; worker never writes PostgreSQL |
6. Result API
| ID |
Scenario |
Expected |
| C2W-R-01 |
Completed row with a valid result artifact |
Validate the complete worker artifact—outer job_id/tenant/attempt/screen/status/time, Page Import inputs, and the existing DesignSpecModel—then return that full validated artifact verbatim |
| C2W-R-02 |
Processing or failed row |
404 from result endpoint; status remains available from GET |
| C2W-R-03 |
result.json has invalid shared result content or lineage |
500; invalid content is not returned |
| C2W-R-04 |
Existing DesignSpecModel validation fails |
500; plugin receives no artifact or partial spec |
| C2W-R-05 |
Valid result is returned |
Response preserves the full artifact fields job_id, attempt, organization_id, project_id, screen_id, status, generated_at, inputs, and spec with no projection, asset signing, or schema translation; the plugin consumes artifact.spec |
| C2W-R-06 |
List request omits pagination |
Apply WF2Des-compatible limit=50, offset=0, and return total before pagination |
| C2W-R-07 |
S3 metadata declares more than 10 MiB, or a stream crosses 10 MiB |
Reject with 500 before validation or abort the bounded stream; never allocate an unbounded full-object buffer |
| C2W-R-08 |
generated_at uses Z or an equivalent +00:00 offset |
Parse and compare the same UTC instant rather than requiring one timestamp spelling |
7. Figma Recovery and Placement
| ID |
Scenario |
Expected |
| C2W-F-01 |
Plugin opens target file after generation completed |
List discovers completed row with materialized=false |
| C2W-F-02 |
Caught build failure |
Partial staging root is discarded; row remains unmaterialized and the next session rebuilds from the immutable result |
| C2W-F-03 |
Plugin process closes midway through build |
Row remains unmaterialized and reopen rebuilds; test records any partial unstamped node, without asserting unsupported automatic cleanup |
| C2W-F-04 |
Placement includes an invalid node ID |
400; no timestamp |
| C2W-F-05 |
Placement targets a processing/failed row |
404; no timestamp |
| C2W-F-06 |
Valid placement |
Backend stamps materialized_at on the completed row and echoes placedNodeId |
| C2W-F-07 |
Placement backend write fails |
Timestamp remains null; later plugin action can retry |
| C2W-F-08 |
Identical or different placement after timestamp exists |
200 with existing timestamp; no second stamp |
| C2W-F-09 |
Prior completed root exists for the same job ID |
Rebuild succeeds first, then the WF2Des swap removes the prior root and preserves a single completed output |
| C2W-F-10 |
Text node carries existing fallback size/weight/color/bbox width |
Shared builder applies fallback before bindings, lets a resolved binding override its field, keeps width bounded and height auto-growing, and records existing font fallback diagnostics when needed |
| C2W-F-11 |
Layout frame carries existing sizing/wrap/bbox-height values |
fixed pins width/height, hug keeps width-pinned auto height, explicit WRAP plus counter_gap is applied, and empty wrap retains only the existing overflow-safety behavior |
| C2W-F-12 |
Code2WF output is materialized |
Existing wf2des stamp/index namespace and root label wf2des · 1.0 are retained |
| C2W-F-13 |
placementTarget resolves on current page / is absent, stale, nested cross-page, or other-page |
Shared placeRoot receives absolute page x/y and leaves the target unchanged / falls back to viewport center |
| C2W-F-14 |
More than 50 completed unmaterialized rows exist for the open file |
Plugin processes rows sequentially and repeatedly queries limit=50&offset=0 until empty; shrinking results do not skip rows |
| C2W-F-15 |
One row fails result fetch/build among valid rows |
Leave it unmaterialized, report it, continue later rows, and stop repeated failure through the bounded no-progress guard |
| C2W-F-16 |
Plugin session expires during open-time discovery |
Prompt for login and retry discovery after authentication |
| C2W-F-17 |
List/result belongs to another Figma file |
Do not fetch or materialize it |
| C2W-F-18 |
Two plugin sessions discover the same row concurrently |
Exercise the shared job-ID stamp/index and idempotent placement, but record that no atomic server claim is provided |
The server stores no placed node ID, claim, retry count, or recovery state. The node ID is request/response data. The planned plugin extension uses root key wf2des with JSON {jobId, specVersion, role: "root"} and document key wf2des_index with {[jobId]: rootId}; PostgreSQL stores only materialized_at.
8. Security
| ID |
Scenario |
Expected |
| C2W-A-01 |
No JWT |
401 |
| C2W-A-02 |
Read session triggers or records placement |
Opaque 404; no existence leak |
| C2W-A-03 |
Cross-project row/result access |
404; no existence leak |
| C2W-A-04 |
Worker role tries PostgreSQL/DocumentDB/Figma |
Denied; role has no such credentials |
| C2W-A-05 |
Result contains credentials or presigned URLs |
Validation rejects publication |
Cross-cutting Checks
These invariants apply across the relevant cases and are verified alongside them.
- One-read Page Import pins (
C2W-Q-01, C2W-Q-02): one verified immutable normalized-manifest read supplies page_result_url, page_result_hash, and capture_hash; missing or corrupt bytes stop the request before dispatch. No PostgreSQL/S3 transaction is claimed.
- Closed worker boundary (
C2W-Q-03, C2W-Q-04, C2W-A-04): the message contains only documented fields and no Figma destination, credentials, or direct database access.
- Full result artifact (
C2W-R-01, C2W-R-05): the result API returns the complete validated worker artifact verbatim. The plugin reads artifact.spec; the API does not project a smaller response or translate the shared spec.
- Shared spec only (
C2W-C-01–C2W-C-15): Code2WF emits the existing DesignSpecModel and node union with canonical defaults, deterministic paths/annotation markers, and visible flagged placeholders for unsupported fidelity.
- Tenant and credential safety (
C2W-S-03, C2W-S-05, C2W-A-01–C2W-A-05): every source/result access is tenant-scoped, and neither artifacts nor responses expose credentials or presigned URLs.
- Immutable retry convergence (
C2W-I-01, C2W-I-02, C2W-I-03, C2W-I-06): redelivery validates and reuses the winning create-only artifact pair; it never overwrites different lineage.
- Plugin-owned Figma writes (
C2W-F-01–C2W-F-18): the server returns data and records materialized_at; native Figma creation, swap, and recovery remain in the authenticated plugin.
Intentionally Out of Scope
Listed so future tests land with the owning feature or layer.
- Page Import build/browser/capture behavior
- navigation or prototype generation
- high-fidelity design generation
- repeated generation with the same job ID
- server-side Figma writes