ImaGen #9: imagen.series (batch tries 1-10 + selection) #9
Reference in New Issue
Block a user
No description provided.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Goal
Let users submit N parallel-ish tries of the same prompt (N in 1..10), group them into a series, and pick the winner. Adds an
imagen.seriesparent table and linksimagen.jobsto it. The worker doesn't really change — it just keeps chewing the queue serially (mRock has one GPU; parallel rendering isn't useful at this layer).Joint plan with paul (flexsiebels/head): mai messages 1637 / 1638 / 1639. m's ask: 2026-05-11 10:40 ("Nice — can we add a number (up to 10) how many tries we want? And then put those into a folder for that series? We can still select.").
Sibling issue on the flexsiebels side: paul filing in
m/flexsiebels.defor the form + grid + selection UI.Why a parent
imagen.seriestable (not just a column)selected_image_idcolumn makes the selection UI trivial — single UPDATE, no orphan-pick logic.countis denormalised so the list page doesn't JOIN + GROUP BY on every render. Acceptable drift; multi-INSERT happens in one transaction.image.series_id IS NULLfor solos,IS NOT NULLfor series members). No backfill of legacy rows.Scope
1. Schema migration
RLS for
imagen.series: same shape asimagen.images/imagen.jobs(owner-scoped SELECT + INSERT + UPDATE viaauth.uid(); service-role bypasses for worker writes).Grants: same authenticated + service_role pattern as #7/#8.
No NOTIFY trigger on
imagen.seriesitself — series creation flows from the flexsiebels form INSERT, then it INSERTs Nimagen.jobsrows in the same transaction. Existingimagen.jobsAFTER INSERT trigger fires N times, worker handles them serially.2. Worker changes (minimal)
When the worker completes a job with
series_idpopulated, it must:series_idonto the insertedimagen.imagesrow (so the list-page queryWHERE series_id IS NULLskips series members from the main grid).The propagation point is the cloud-sync writer (
internal/cloud/). PassseriesID(nullable UUID) through the writer's input struct. Series-aware in the data layer; everything else unchanged.3. Tests
internal/worker/: job-with-series_id produces image row with the same series_id propagated.4. Smoke
With the worker running, INSERT a series + N child jobs via mcp__supabase:
Expected within ~25-30s (3x ~8s FLUX schnell renders, serial): three
imagen.imagesrows all sharing the sameseries_id, threeimagen.jobsrows all instatus='done'withimage_idpopulated. UPDATE the series'selected_image_idto pick one. List-page queryWHERE series_id IS NULLshows no new rows (the series members are hidden from the main grid).Acceptance criteria
imagen.seriestable + RLS + indexes exist;imagen.jobs.series_id+series_idx+ index exist;imagen.images.series_id+ index exist.imagen.imagesrows carry the matchingseries_id.WHERE series_id IS NULL) hides series members from the flat grid — series surfaces as a single card (handled flexsiebels-side).imagen.series.selected_image_idcan be set to any of the series'imagen.images.idvalues; FK enforces correctness; ON DELETE SET NULL handles image deletion gracefully.go build ./... && go test ./...clean.Out of scope
/imagine. m can bulk-delete via the series view if storage grows.selected_image_idis enough for v3.Refs
Workflow
Coder/gitster role. Phases mirror #7/#8:
series_idfrom job to image), unit test.Head reviews + merges --no-ff into main + comments + applies
donelabel.Phase 1 + 2 landed — Phase 3 waiting on worker redeploy.
Phase 1 — schema migration (DONE)
Migration
imagen_series_initapplied to prod Supabase. Shape:imagen.series(id, owner_user_id, prompt, backend, model, width, height, steps, style, count CHECK 1..10, selected_image_id REFERENCES imagen.images(id) ON DELETE SET NULL, created_at).imagen.jobs+=series_id UUID FK -> imagen.series(id) ON DELETE SET NULL,+ series_idx INT. Partial index on (series_id, series_idx) WHERE series_id IS NOT NULL.imagen.images+=series_id UUID FK -> imagen.series(id) ON DELETE SET NULL. Partial index WHERE series_id IS NOT NULL.imagen.series: owner SELECT/INSERT/UPDATE viaauth.uid(). Grants: authenticated + service_role.imagenalready inpgrst.db_schemas.Phase 2 — worker pipeline tweak (DONE)
Commit: https://mgit.msbls.de/m/ImaGen/commit/64120c2
worker.Job+=SeriesID. Claim SQL now scansCOALESCE(series_id::text,'').cloud.SyncRequest+=SeriesID.insertRowwritesseries_idonly when non-empty (solo path keeps the column NULL, list-page queryWHERE series_id IS NULLkeeps showing solo runs).maybeCloudSyncthreadsseriesIDthrough;generate.go(CLI solo path) passes"",cmd/imagen/worker.gopassesjob.SeriesID.TestWorker_PropagatesSeriesIDToPipeline,TestWorker_SoloJobLeavesSeriesIDEmpty,TestSyncWritesSeriesID,TestSyncOmitsSeriesIDWhenEmpty. All green; full suite clean.Phase 3 — pending
N=3 smoke needs the new binary on mriver — current systemd service runs the pre-#9 binary (claim SQL returns 10 fields, doesn't read
series_id). Coordinating redeploy with head, then smoke + selected_image_id verification land here.Phase 3 — N=3 smoke (PASS).
Inserted series + 3 jobs in one transaction:
Series id:
2047f1c5-04da-47b7-8127-8bfe5322dad6.4bf4b798-...beb6f092047f1c5-...22dad6934a8602-...bbb18d42047f1c5-...22dad6afc4e926-...279a5e22047f1c5-...22dad6Total wall-clock: ~22s for three 1024x1024 FLUX schnell renders. All three
imagen.images.series_idcolumns match the parent — propagation works end-to-end (claim SQL → worker.Job.SeriesID → cloud.SyncRequest.SeriesID → row.series_id).Acceptance checks
imagen.series+ RLS + indexes exist; jobs.series_id/series_idx + index exist; images.series_id + index exist (migrationimagen_series_init).series_id=2047f1c5-.... ✓WHERE series_id IS NULLreturns zero of the three smoke rows — series members are hidden from the flat grid. ✓selected_image_idset to934a8602-...(series_idx=2). FK rejects bogus UUIDs (verified with a foreign_key_violation roundtrip — value stays at the real winner). ✓generate.go(CLI) and the worker both treat empty SeriesID as "skip propagation"; cloud.insertRow omits theseries_idkey entirely when empty. Unit testsTestSyncOmitsSeriesIDWhenEmptyandTestWorker_SoloJobLeavesSeriesIDEmptylock the behaviour in. ✓go build ./... && go test ./...clean.Phases 1+2 commit: https://mgit.msbls.de/m/ImaGen/commit/64120c2
Merge commit: https://mgit.msbls.de/m/ImaGen/commit/623dd29
Ready for
donelabel.