refactor: wrap comic page-render + refine-render as creative tools (route-level persistence) (#2241)#2244
Merged
Merged
Conversation
…th route-level persistence (#2241)
Owner
Author
|
Review gate (claude + codex): no blocking issues. Two non-blocking consistency notes, deferred as out-of-scope for this mirror PR:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #2241
Summary
Completes the #2220 audit clause the covers slice (#2234) deferred: gives the comic page render and refine-render route handlers the same treatment #2234 gave covers. The enqueue+persist flow moves out of the route handlers into shared service entry points, then those are wrapped as Creative Director tools so the routes and the CDO orchestrator share ONE code path.
Mirrors the
renderComicCover/makeCoverRenderHandlerstructure exactly.Service (
server/services/pipeline/visualStages.js)persistComicPageSlot(issueId, pageIndex, {...})— shared helper that splices the in-flight render slot ontostages.comicPages.pages[pageIndex].{proofImage|finalImage}through the serializedupdateStageWithLatestissue write tail (404s on an out-of-range index).renderComicPage(issueId, options)— enqueue (enqueueVisualComicPage) + persist in one call.refineComicPageRendernow persists its slot too and returns{ issue, stage }.Routes (
server/routes/pipeline/issues.js)POST .../pages/:pageIndex/renderand.../refine-rendernow delegate to the shared entry points (route keeps its up-front page-existence pre-flight + Zod validation + response shaping). Removed the now-duplicated inline enqueue+persist and the now-unusedenqueueVisualComicPage/buildRenderSlot/slotKeyForVariantimports.Creative tools (
server/services/creative/tools/pipeline.js)pipeline_renderComicPageandpipeline_refineComicPageRendertools (COST_RENDER, longRunning), with option shapes mirroring the route Zod schemas. Registered automatically viaPIPELINE_TOOLS.The persist runs inside the write tail's compute step, so a concurrent page edit or sibling render can't be reverted by a stale snapshot. The filename hook only attaches the completed image when the slot already carries the returned jobId — the reason this write must live behind the shared entry points, not only in the route.
Test plan
server/services/pipeline/visualStages.test.js— newrenderComicPage (enqueue + persist)block (proof slot, final+fromProof, 404); refine happy-path now asserts the persisted slot.server/services/creative/toolRegistry.test.js— new dispatch tests for both tools (charges one render action; Zod gate rejects missingpageIndex/instruction).server/routes/pipeline.test.js— mock rewired to drive the real write tail through the new service entry points; page-render/refine-render persistence assertions preserved.Refs #2220. Context:
docs/plans/2026-07-04-creative-director-orchestrator.md, epic #2182.