AI Des2WF — Infrastructure
Des2WF's own deployment surface. The shared platform infrastructure is documented in Infrastructure.
Compute
| Item | Value |
|---|---|
| Runtime | Python 3.12 on AWS Lambda, container image |
| App | apps/des2wf — a peer Lambda to apps/wf2des, not a run family inside it |
| Batching | SQS with ReportBatchItemFailures, partial-batch semantics |
| Shared code | packages/figma-ir — imported one-way by both apps, never the reverse |
Why a second Lambda rather than a second run family. The WF2Des generation module is ~2,700 LOC with five inline post-passes and a measurably non-deterministic selection path — three runs of one screen produced three distinct specs. Des2WF's engine shares none of that machinery, so putting it in the same module inherits the guard pile and buys nothing. Isolation is the reason, not deploy hygiene.
Queues and triggers
| Trigger | Owner | Des2WF's use |
|---|---|---|
| DES2WF queue | backend | Dedicated transport for generation and post-terminal review; messages retain edge=des2wf, review also carries kind=render_review |
wf2des-events intake queue |
AI side | reused for plugin-originated events; the backend holds send permission only |
| EventBridge schedule | AI side | none for des2wf. There is no periodic sweep to run: the WF component library is registered on demand from the plugin |
Job IDs are shared through the PostgreSQL wf2des table, not through a shared queue.
The backend routes queueType=des2wf to SQS_DES2WF_QUEUE_URL; the worker distinguishes
generation from review using kind. Kit registration still uses the shared events path.
Storage and secrets
| Item | Value |
|---|---|
| Result bucket | backend-owned AI bucket, prefix {org}/{proj}/des2wf/ |
| Snapshot storage | the full per-node REST envelope, maps retained |
| DocumentDB | guinness_v2; see Stores for result, kit, shared and scoped-override collections |
| Figma access | split by who initiates the work — see below |
Two credentials, split by initiator. A snapshot taken with an authority unrelated to the requester lets a user trigger a file they cannot open, and 404s on files the user CAN open when the service account is not a member — both measured on real files, which is why no service-account PAT exists on this path. The split:
| Path | Credential |
|---|---|
| Design-snapshot capture (a user action, backend-side) | the requesting user's own PAT from the platform figma_token table |
| Worker-side Figma reads (registration sweep — no user on that path) | the org's private OAuth app grant (Authorization: Bearer), stored encrypted in figma_oauth_grant with an AI-owned key; figma_pat env as fallback for a deploy without the app configured |
The two credentials have different reachability, so a failure on one path is not evidence about the other, and the error must say which credential was used.
Environment
| Variable / config | Description |
|---|---|
DOCUMENTDB_CONNECTION_STRING, DOCUMENTDB_NAME, DOCUMENTDB_CA_PATH |
DocumentDB access, guinness_v2 |
| per-collection names | env-overridable, including the new wireframe_component |
SQS_DES2WF_QUEUE_URL |
Backend setting for the dedicated generation/review queue |
wf2des-events queue URL |
AI-owned intake |
WEBHOOK_BASE_URL, WEBHOOK_API_KEY |
ai-status endpoint and its X-API-Key |
| result bucket + key prefix | {org}/{proj}/des2wf/ |
FIGMA_OAUTH_* + grant encryption key |
worker-side Figma auth — the OAuth app grant (client id/secret live backend-side; the worker holds the AI-owned encryption key and only ever refreshes). figma_pat remains as fallback |
| snapshot byte cap | 20 MB default, env-overridable; enforced on the des2wf capture path — wf2des has no such gate |
DEFAULT_ORGANIZATION_ID |
single-tenant default |
| model tiers | Parse is deterministic. Both modes use the configured strong model for contextual graphic classification when source PNG evidence is available; kit also performs sampled variant selection. Post-render review is a separate vision call. Record model and prompt versions; neither mode guarantees repeat-run identity |
PROMPT_VERSION, SPEC_VERSION |
pinned. Note nothing in the system compares SPEC_VERSION, so it is traceability, not a safety gate |
Graphic-classification runtime
STRONG_MODELsupplies the vision model; its provider credentials must be available to the worker.DES2WF_VERDICT_TABLE_NAMEretains the default collection namedes2wf_verdict, but generation reads only scopedrecord_type=graphic_override_v1records, not legacy verdicts.- Source evidence is an optional S3 PNG captured backend-side with the requesting user's PAT, pinned to the JSON snapshot's Figma version and absolute bounds. The worker reads S3; it does not use its own Figma credentials to recapture generation evidence.
- Source PNGs are content-addressed by source and render hashes. Review PNGs are separate per-job objects; see Stores.
- Current classification constants: 6 candidates/batch, 3 concurrent calls, 180 seconds, maximum 32,000,000 source pixels. These are classification limits, not an end-to-end job timeout.
- Source PNG downloads also have a 20 MiB byte cap. The 20 MB snapshot cap is separate from the PNG pixel cap. Invalid images, unavailable providers and exhausted classification budgets preserve artwork and record a fallback; they do not require the whole generation to fail.
- Structured logs and
graphic_classificationdistinguish completed, partial and fallback classification. A completed generation alone does not imply every candidate was classified.
Deploy ordering
Order matters here for a reason that has already bitten this project once: a route that acks on enqueue will DLQ envelopes while the client shows success.
- Migration first — the
edgecolumn,source_node_id, and the recreated partial unique index. - Worker before backend — the worker must be able to consume
edge=des2wfbefore anything can send it. - Backend before plugin — the plugin's des2wf control must not be reachable before the endpoints answer.
eventswidening as one change across three repos — the plugin field, the backend enum and the internal-api literal ship together, or the MVP's own score cannot reach the server.
CI
Mirrors the WF2Des workflow: lint, type-check, unit and component tests, container build, deploy on merge. Two additions specific to this build:
- the shared package lands behind re-export shims so the existing suite is untouched on day one; the shim-deletion commit is separate and independently revertible, and it is the one that carries the import churn;
- a guard test that fails if a des2wf run can write PostgreSQL, since that boundary is the system's main invariant.