Skip to content

CDO creative render tools with route-level cover persistence#2234

Merged
atomantic merged 1 commit into
mainfrom
claim/issue-2220
Jul 6, 2026
Merged

CDO creative render tools with route-level cover persistence#2234
atomantic merged 1 commit into
mainfrom
claim/issue-2220

Conversation

@atomantic

Copy link
Copy Markdown
Owner

Summary

Adds four cover-render creative tools so the Creative Director orchestrator (epic #2182) can render comic-issue and volume (season) covers, and extracts the enqueue+persist flow the routes and tools now share.

  • New creative tools (server/services/creative/tools/pipeline.js): pipeline_renderComicCover, pipeline_renderComicBackCover, pipeline_renderVolumeCover, pipeline_renderVolumeBackCover — each a thin conductor over a shared service entry point, charged as render against the daily action budget, with a Zod schema + OpenAI-function parameters fragment mirroring the route's render knobs.
  • Why more than a bare enqueue was needed: the media-job filename hook attaches the finished image only if the target cover slot already carries the returned jobId. That slot write used to live in the route factory (routes/pipeline/covers.js#makeCoverRenderHandler), so wrapping the bare enqueueComicCover-style service in a tool would silently drop orchestrated covers (the exact reason the tool was deferred in CDO Phase 1: Creative Tool Registry + gated dispatch (creative autonomy domain, budget, ledger) #2183).
  • Shared enqueue+persist entry points (server/services/pipeline/visualStages.js): renderComicCover/renderComicBackCover persist onto stages.comicPages.{cover|backCover} through the serialized updateStageWithLatest series write tail; renderVolumeCover/renderVolumeBackCover persist onto series.seasons[].{cover|backCover} through updateSeasonOnSeries. The four cover-render routes now call these, shrinking the route factory to validation + dispatch + response shaping — so route and orchestrator share ONE code path.
  • Serialized writes / script-gate preserved: persistence goes through the single-tail-per-shared-file write queues (per the repo's async-PATCH-race rule), and the script-gate semantics are intact — an absent coverScript/backCoverScript preserves the persisted concept, an empty string clears it, so a render can't clobber a concurrent blur-save of the script field.

Cover render is the primary deliverable of #2220; wrapping the remaining route-persisted render actions (comic page render / refine-render) as tools stays tracked on the issue.

Test plan

  • server/services/creative/toolRegistry.test.js — new cases: dispatch pipeline_renderComicCover through the shared service + charge one render action; pipeline_renderVolumeCover splits seriesId/seasonId from options; Zod gate rejects a call missing its required id.
  • server/services/pipeline/visualStages.test.js — new renderComicCover/renderComicBackCover and renderVolumeCover/renderVolumeBackCover describe blocks asserting the proof/final slot lands with fromProof provenance and the script-gate (absent preserves / present writes).
  • server/routes/pipeline.test.js — updated the visualStages.js mock to drive persistence through the real issues/series write tails (persistence moved out of the route), keeping the cover-render route tests' preserve/clear assertions green.
  • Ran the three target suites + creative/ + the full server suite (excluding *.db.test.js): all branch-related tests pass. The only failures in the full run (visionCli, runner, dataRoot, installState) are pre-existing and environmental — confirmed identical on a clean checkout of this branch's base.

Refs #2220

Register four cover-render creative tools (pipeline_renderComicCover,
renderComicBackCover, renderVolumeCover, renderVolumeBackCover) so the
Creative Director orchestrator can render comic-issue and volume covers.

A bare enqueue is not enough: the media-job filename hook attaches the
finished image only if the target cover slot already carries the returned
jobId, and that slot write used to live in the route factory
(routes/pipeline/covers.js#makeCoverRenderHandler). Wrapping the bare
enqueueComicCover-style service in a tool would silently drop orchestrated
covers.

Extract the enqueue+persist flow into shared service entry points in
visualStages.js -- renderComicCover/renderComicBackCover (persist onto
stages.comicPages.{cover|backCover} via the serialized updateStageWithLatest
series write tail) and renderVolumeCover/renderVolumeBackCover (persist onto
series.seasons[].{cover|backCover} via updateSeasonOnSeries) -- so the four
cover-render routes and the four orchestrator tools share ONE code path.
The persist keeps script-gate semantics (absent preserves, empty clears)
and serializes against a concurrent blur-save on the same record.

Refs #2220
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant