The Velvet Paradox / Creative automation / 2026
Following image jobs from submission to usable candidates.
An n8n render workflow preserves local job identity while polling a provider, then requires returned image URLs before creating candidates.
- ROLE
- Software engineering
- STATE OF THE BUILD
- Prototype
- RECORD UPDATED
- PUBLIC SOURCE
- View on GitHub
THE WORK
The project.
The Velvet Paradox gives a submitted image request a local history while the provider is still working. Its n8n workflow records the queued job, retains the concept and variant it belongs to, and follows the provider's status and result locations. Completion creates one candidate per returned image only when image URLs are present. Failed and timed-out jobs retain their own outcomes instead of appearing as empty successes.
Keeping that context available requires care because a Data Table write can replace the current n8n item. The workflow restores job identity for later nodes, but its poll normalizer also reloads the initial counter. That possible reset still needs a loop test. This account covers the exported workflow and maintenance logic, not a verified provider render or live recovery run.
IMPLEMENTATION
Design choices.
- The workflow restores identity after storage nodes replace the payload. Later writes need the original concept and job, but progress fields such as the attempt counter must come from the latest loop pass rather than the initial snapshot.
- The queued record precedes submission. It makes a pending request locally traceable, although the time-dependent job ID identifies an attempt rather than deduplicating replayed requests. A repeated submission can still create another provider attempt.
- Candidate creation requires artifacts as well as a completed status. An empty completion can't become a candidate; valid output produces a separate candidate for each image URL returned.
- Provider failure, polling timeout and stale-work recovery have separate records. Each explains a different stopping point. The maintenance path doesn't substitute for proving that the normal poller reaches its own attempt limit.
HOW IT FITS TOGETHER
Architecture.
- The submit-and-poll workflow validates the concept, variant and prompt, separates context from job fields, and stores a queued record before calling the provider. The pending request therefore already has a local attempt identity.
- Provider normalization extracts the request identity and the status and result locations. After Data Table writes return row-shaped output, the workflow joins back the original context so later operations still identify the same concept and job.
- Wait, poll, normalize and increment nodes repeat while the provider is pending. The workflow records running state and has separate completion, failure and timeout branches; the counter must survive every pass for the configured attempt limit to work.
- The completion branch requires image URLs before emitting candidates. A separate maintenance workflow finds stale jobs and expired concept reservations, providing a recovery path for work whose original polling execution no longer advances.
Explore the architecture map9 components · 11 connections
Render jobs, provider polling and stale-work recovery
Submission and maintenance share durable job state; image candidates are emitted only after result validation.
Job preparation
Provider execution
Durable state
Scroll or drag the background to move. Use the zoom buttons to resize.Arrow keys move between components. Enter selects.
Choose a component to explore
Select a numbered component on the map or use the component menu. Its details and connections will appear here.
No component selected.
All connections (11)
- 01 · Envelope validation → 02 · Context and job envelopeValidated input · Direct call
- 02 · Context and job envelope → 03 · Job tableQueued job · Direct call
- 02 · Context and job envelope → 04 · Submit requestProvider payload · Direct call
- 04 · Submit request → 05 · fal rendering jobCreate render job · Async task
- 05 · fal rendering job → 06 · Poll and normalizeStatus and result · Async task
- 06 · Poll and normalize → 05 · fal rendering jobContinue polling · Response / return
- 06 · Poll and normalize → 03 · Job tableRunning / failure / timeout · Direct call
- 06 · Poll and normalize → 07 · Image-result validationCompleted payload · Direct call
- 07 · Image-result validation → 08 · Image candidatesValidated images · Direct call
- 09 · Maintenance recovery → 03 · Job tableStale-job updates · Direct call
- 03 · Job table → 09 · Maintenance recoveryAge and state · Direct call
MADE WITH
n8n · Telegram · Data Tables · JavaScript · HTTP workflows · fal
CHECKS & RESULTS
What was checked.
A source review shows what the code does. It is not a fresh test of the running app.
Code and development records reviewedReviewed
The code, tests and available development records were checked. Reported test results keep their original scope. No fresh app or live deployment check was run for this write-up.
- Scope of this check
- Code review, not a fresh run of the app
NEXT
Still to work through.
A provider stub that never leaves pending would make the remaining polling question concrete. I'd record the counter on every pass and check for one terminal update at the configured limit, then exercise retries alongside stale-job recovery. The counter-reset concern comes from source inspection; its runtime effect hasn't been reproduced in this review.