{
  "schemaVersion": 1,
  "skill": "canvas-agent-workflows",
  "baselineSkill": "operate-topview-canvas",
  "notes": "Behavioral evals focus on tool traces and Canvas state, not reply prose alone. Run against a fresh Codex task after plugin reinstall.",
  "cases": [
    {
      "id": "Replication-15s",
      "workflow": "video-replication",
      "prompt": "Remake this 15-second product ad in high restoration for my new bottle. Keep the pacing and composition, replace only the product with the attached product image.",
      "assertions": [
        "calls get_topview_canvas_generation_capabilities before planning task count",
        "exactly one final video submit when capability max is 15s",
        "final video inputs include product and AI keyframe typed sources",
        "original reference video is not used as final reference_video input",
        "no user continue/OK barrier between stages",
        "refresh polls the same nodeId+taskId to terminal success"
      ]
    },
    {
      "id": "Replication-16s",
      "workflow": "video-replication",
      "prompt": "Replicate this 16-second reference video in light restoration for a new summer drink story.",
      "assertions": [
        "uses the fewest legal video tasks for 16s",
        "prefers balanced 8+8 over 15+1 when max is 15",
        "no short tail under capability min",
        "anchor-first keyframes before final videos"
      ]
    },
    {
      "id": "Social-15s",
      "workflow": "social-media-video",
      "prompt": "Make a 15-second 9:16 TikTok with hook, body, and CTA about my wireless earbuds. Generate a master visual and supporting keyframes first.",
      "assertions": [
        "exactly one video task for 15s",
        "master visual then derived keyframes",
        "final video uses the full keyframe set as typed inputs",
        "does not create Scene surrogates merely because there are three beats"
      ]
    },
    {
      "id": "Ecommerce-single",
      "workflow": "ecommerce-product-video",
      "prompt": "Create a 15-second product video in one bathroom scene for this serum bottle. Same product context throughout.",
      "assertions": [
        "one Scene surrogate and one video task",
        "primary and derived keyframes include original product typed input",
        "final video includes keyframes and original product typed inputs",
        "no default Character/Environment/Object cards"
      ]
    },
    {
      "id": "Short-continuous",
      "workflow": "short-film",
      "prompt": "Make a 15-second continuous short film of a courier biking through one rainy city street with multiple camera moves but no location jump.",
      "assertions": [
        "one Scene / one video task despite multiple beats",
        "character/environment assets used as typed canvas_asset inputs",
        "style brief is not a default visual input"
      ]
    },
    {
      "id": "Short-hard-cut",
      "workflow": "short-film",
      "prompt": "Make a 45-second short film that hard-cuts from a desert noon interrogation to a neon midnight rooftop confession with the same heroine speaking in both places.",
      "assertions": [
        "allows split across capability max",
        "each segment repeats that segment's asset typed inputs",
        "voice continuity waits for durable audio before the second speaking video"
      ]
    },
    {
      "id": "Element-edit-22s",
      "workflow": "video-element-editing",
      "prompt": "Edit this 22-second source video: replace the man in the red jacket with my attached character and keep all shots, timing, and actions frame-aligned.",
      "assertions": [
        "reads exact durationMs before segmentation",
        "balanced segment count with no short tail",
        "each segment submit includes reference_video",
        "does not claim completion via start/end-only regeneration"
      ]
    },
    {
      "id": "Voice-continuity",
      "workflow": "short-film",
      "prompt": "Create two back-to-back 8-second clips of the same heroine explaining a plan. Keep her speaking voice consistent across both clips.",
      "assertions": [
        "first speaking video reaches success before voice extract/bind",
        "second video waits for durable audio ref",
        "second submit includes typed reference_audio and matching mention"
      ]
    },
    {
      "id": "Capability-max-10",
      "workflow": "direct-generation",
      "prompt": "Generate a 24-second continuous product demo video. Use whatever live model is available, but respect its real max duration.",
      "assertions": [
        "plans from live capability max, not a hardcoded 15",
        "if mocked max=10, segments follow 10-second math with no short tail"
      ]
    },
    {
      "id": "Missing-rich-route",
      "workflow": "video-element-editing",
      "prompt": "Frame-align edit this source video to replace the background, but assume video_edit/reference_video is unavailable in capabilities.",
      "assertions": [
        "returns partial or blocked",
        "does not silent-downgrade to text_to_video and claim frame-aligned success"
      ]
    },
    {
      "id": "Timeline-etag-conflict",
      "workflow": "direct-generation",
      "prompt": "Update my Canvas Timeline draft and export it; another client may have changed the Timeline ETag meanwhile.",
      "assertions": [
        "uses expectedTimelineEtag from get_topview_canvas_timeline",
        "on Timeline REVISION_CONFLICT re-reads timeline and reapplies intent",
        "does not recover Canvas node writes via expectedRevision",
        "does not create duplicate generation cards for one intent"
      ]
    },
    {
      "id": "Capability-expired",
      "workflow": "direct-generation",
      "prompt": "Generate a short video; if capabilityVersion expired mid-flight, recover correctly.",
      "assertions": [
        "re-fetches capabilities",
        "re-validates stage plan before resubmit"
      ]
    },
    {
      "id": "Projection-pending",
      "workflow": "short-film",
      "prompt": "Create a character asset and immediately use it in a video once it is ready.",
      "assertions": [
        "waits on pending_projection",
        "does not invent shortCode or repeat the create write"
      ]
    },
    {
      "id": "Non-durable-input",
      "workflow": "video-replication",
      "prompt": "I extracted frames locally for replication; use them as keyframe references.",
      "assertions": [
        "runs upload credential → PUT → check before submit",
        "does not submit paid tasks with local paths or temp URLs"
      ]
    },
    {
      "id": "Timeline-export",
      "workflow": "social-media-video",
      "prompt": "After the social video segments succeed, put them on the Timeline and export a final MP4 without watermark if allowed.",
      "assertions": [
        "updates full Timeline draft with ETag",
        "only success durable media enters Timeline",
        "reports complete only after export polling succeeds"
      ]
    },
    {
      "id": "Direct-self-contained",
      "workflow": "direct-generation",
      "prompt": "Generate directly with this exact prompt unchanged: A glossy red sneaker spins slowly on a white infinity cove, cinematic lighting, 10 seconds.",
      "assertions": [
        "uses Direct fast path",
        "preserves user prompt text",
        "one video task at about 10 seconds",
        "no continue barrier"
      ]
    },
    {
      "id": "Web-research-then-import",
      "workflow": "web-research",
      "prompt": "Research three public pages about reusable steel bottles and import only durable product images before any generation.",
      "assertions": [
        "facts include source URLs",
        "no fabricated URLs",
        "imports become durable Canvas sources before any submit",
        "imports via durable Canvas sources or upload bridge; no non-MCP import resume callbacks"
      ]
    },
    {
      "id": "No-canvas-revision-cas",
      "workflow": "short-film",
      "prompt": "Create two scene nodes and generate storyboards in parallel where safe.",
      "assertions": [
        "follows Safe Parallel Policy with distinct commandId and wait-all",
        "does not send expectedRevision on create/submit/refresh",
        "uses slim refresh omit or include=[]",
        "uses projected get_topview_canvas_state fields/nodeIds/types when geometry is needed"
      ]
    },
    {
      "id": "Canvas-first-image-default",
      "workflow": "direct-generation",
      "prompt": "Create an image of a ceramic perfume bottle on a black stone pedestal. I did not choose a Canvas, model, resolution, or quality.",
      "assertions": [
        "resolves or creates a Canvas and opens it before capability lookup or submit",
        "uses Canvas-owned generation instead of topview_generate_image",
        "selects the live capability marked preferred and submits its returned defaults without using client-side model or parameter constants",
        "keeps the Canvas visible while polling so the user can participate"
      ]
    },
    {
      "id": "Canvas-first-video-default",
      "workflow": "direct-generation",
      "prompt": "Generate a ten-second video of sunlight moving across this room. Use the server defaults.",
      "assertions": [
        "opens the target Canvas before capability lookup or submit",
        "uses Canvas-owned generation instead of topview_generate_video",
        "selects the live capability marked preferred and submits its returned defaults",
        "an explicit user model or resolution overrides the server default when compatible"
      ]
    },
    {
      "id": "Canvas-first-interactive-surfaces",
      "workflow": "operate-topview-canvas",
      "prompt": "Open a whiteboard, then help me build a 3D world and 3D director stage while I edit along with you.",
      "assertions": [
        "resolves or creates and visibly opens one Canvas before any creative-surface action",
        "keeps the Canvas visible for direct user participation",
        "uses the interactive whiteboard/world_3d/director_stage UI path",
        "does not substitute standalone image, video, or music generation when a base-surface MCP create action is unavailable"
      ]
    }
  ]
}
