[{"slug":"ZV-2026-0238","server_name":"spriteship.com","severity":"breaking","title":"spriteship.com: Field regenerate was removed from generate_character_turn input; consumers still sending it may be rejected or silently ignored.","summary":"[safe] Tool set_asset_collision_body was added. [safe] Description of generate_character_animation changed (15% word delta). [safe] Description of generate_character_turn changed (16% word delta). [breaking] Field regenerate was removed from generate_character_turn input; consumers still sending it may be rejected or silently ignored. [safe] Description of get_character changed (24% word delta). [safe] Description of get_job changed (16% word delta).","changes":[{"kind":"tool_added","tool":"set_asset_collision_body","detail":"Tool `set_asset_collision_body` was added.","severity":"safe"},{"kind":"description_changed","tool":"generate_character_animation","after":"PAID, and the cost MULTIPLIES BY THE NUMBER OF ANIMATIONS (each is its own image-to-video call, ~400 credits at defaults). This is real motion — a walk cycle, an attack, an idle bob — not the 1-frame still that create_animation_from_pose produces. Read the character's gameType and use the standard animation names for it (get_character shows what already exists); the project gameType is irrelevant after character creation. A topdown character inside a platformer project still uses top-down prompts and directional behavior. A name that already exists is NEVER replaced: the server allocates the next numeric slug (walk → walk_2 → walk_3), and the returned animations list contains the resolved names. Ask the user which animations they want before spending: 4 animations cost 4x. Every animation defaults to 2 seconds, including walks, runs, attacks, and loops. Omit animDurations and customAnims[*].duration unless the user explicitly asks for a different clip length; never infer a longer duration from the motion or from the fact that it loops. If the character came from a 2x2 create, there are FOUR siblings and animating is per-character: show the user the characterPreviews from get_job and have them pick one before you spend. For multi-direction sets, mirrorAnims gives you FREE flipped copies of a direction generated in the same call (walk_left from walk_right) — prefer a real generation when the character is asymmetric, because a held item switches sides under a mirror. The server chooses the release-new-animation-pipeline rollout for this API-key owner; there is no flag argument to set. When the user wants stored poses as the actual video endpoints, call list_character_poses and pass their ids through poseFirstFrameIds / poseLastFrameIds. Omit those maps to let the server plan anchors automatically; never pass a pose URL. Before each new clip the server classifies the effective anchor as empty-handed, held, or unclear and adds the matching inventory-preservation lock automatically; there is no inventory argument to send. For eligible direction-named topdown walk/run clips, that automatic planning may create and cache a special mid-walk pose plus an internal 360 rotation; its one-time surcharge is included in the dry-run quote. Do NOT call generate_character_turn merely to prepare an animation — that explicit visible turn is a separate action. The dry-run response includes animationPipelineAssignmentToken; copy it verbatim into the confirmed call so the quoted rollout decision cannot change while the user is deciding. If it expires, run the same dry-run again. Returns { jobId, animations } — poll get_job. When the job reaches done, it returns an animationQualityGate requiring get_character; finish that review/repair loop before exporting or saying the animation is ready. A prompt that composes too long for the model is rejected with PROMPT_TOO_LONG before anything is charged, and the response names the animation. Check isTemplate on that entry: false means YOUR text is what is long, so shorten it; true means the shipped template is over the ceiling and no prompt you send can fix it — report it rather than retrying. DEFAULTS TO A COST PREVIEW — see the dryRun argument.","before":"PAID, and the cost MULTIPLIES BY THE NUMBER OF ANIMATIONS (each is its own image-to-video call, ~400 credits at defaults). This is real motion — a walk cycle, an attack, an idle bob — not the 1-frame still that create_animation_from_pose produces. Read the character's gameType and use the standard animation names for it (get_character shows what already exists); the project gameType is irrelevant after character creation. A topdown character inside a platformer project still uses top-down prompts and directional behavior. A name that already exists is REGENERATED. Ask the user which animations they want before spending: 4 animations cost 4x. If the character came from a 2x2 create, there are FOUR siblings and animating is per-character: show the user the characterPreviews from get_job and have them pick one before you spend. For multi-direction sets, mirrorAnims gives you FREE flipped copies of a direction generated in the same call (walk_left from walk_right) — prefer a real generation when the character is asymmetric, because a held item switches sides under a mirror. The server chooses the release-new-animation-pipeline rollout for this API-key owner; there is no flag argument to set. When the user wants stored poses as the actual video endpoints, call list_character_poses and pass their ids through poseFirstFrameIds / poseLastFrameIds. Omit those maps to let the server plan anchors automatically; never pass a pose URL. Before each new clip the server classifies the effective anchor as empty-handed, held, or unclear and adds the matching inventory-preservation lock automatically; there is no inventory argument to send. For eligible direction-named topdown walk/run clips, that automatic planning may create and cache a special mid-walk pose plus an internal 360 rotation; its one-time surcharge is included in the dry-run quote. Do NOT call generate_character_turn merely to prepare an animation — that explicit visible turn is a separate action. The dry-run response includes animationPipelineAssignmentToken; copy it verbatim into the confirmed call so the quoted rollout decision cannot change while the user is deciding. If it expires, run the same dry-run again. Returns { jobId, animations } — poll get_job. A prompt that composes too long for the model is rejected with PROMPT_TOO_LONG before anything is charged, and the response names the animation. Check isTemplate on that entry: false means YOUR text is what is long, so shorten it; true means the shipped template is over the ceiling and no prompt you send can fix it — report it rather than retrying. DEFAULTS TO A COST PREVIEW — see the dryRun argument.","detail":"Description of `generate_character_animation` changed (15% word delta).","severity":"safe","descriptionDelta":0.14675767918088733},{"kind":"description_changed","tool":"generate_character_turn","after":"PAID (~400 credits — ONE 2-second rotation video). Spins the character through a full 360 so the sprite exists from every side; its frames are also what the directional-pose extractor reads, which is what makes top-down characters usable in more than one facing (isometric projects use top-down characters). ONLY topdown and isometric characters are supported — any other game type errors 400 TURN_NOT_SUPPORTED (topdown_overhead: the engine rotates the sprite image; platformer/point_and_click: side/front views, mirror instead). Eligibility reads the STORED CHARACTER gameType, not its project: a topdown character inside a platformer project is supported. This explicit visible turn is separate from the internal mid-walk rotation that generate_character_animation may plan for eligible directional walk/run clips; do not call it as mandatory setup for every animation. Lands as the animation \"turn\", or \"turn_<seedPoseId>\" when seeded from a pose. An existing turn is NEVER replaced: an occupied name becomes turn_2, turn_3, and so on. It 409s (ENTITY_BUSY) while ANY other job is running on the character, because it rebuilds the spritesheet: poll that job first. Returns { jobId, animation } — poll get_job. DEFAULTS TO A COST PREVIEW — see the dryRun argument.","before":"PAID (~400 credits — ONE 2-second rotation video). Spins the character through a full 360 so the sprite exists from every side; its frames are also what the directional-pose extractor reads, which is what makes top-down characters usable in more than one facing (isometric projects use top-down characters). ONLY topdown and isometric characters are supported — any other game type errors 400 TURN_NOT_SUPPORTED (topdown_overhead: the engine rotates the sprite image; platformer/point_and_click: side/front views, mirror instead). Eligibility reads the STORED CHARACTER gameType, not its project: a topdown character inside a platformer project is supported. This explicit visible turn is separate from the internal mid-walk rotation that generate_character_animation may plan for eligible directional walk/run clips; do not call it as mandatory setup for every animation. Lands as the animation \"turn\", or \"turn_<seedPoseId>\" when seeded from a pose. It 409s (ANIMATION_EXISTS) if that animation already exists — pass regenerate:true to replace it, which also clears the cached frames so you actually get new output. It also 409s (ENTITY_BUSY) while ANY other job is running on the character, because it rebuilds the spritesheet: poll that job first. Returns { jobId, animation } — poll get_job. DEFAULTS TO A COST PREVIEW — see the dryRun argument.","detail":"Description of `generate_character_turn` changed (16% word delta).","severity":"safe","descriptionDelta":0.16083916083916083},{"kind":"input_property_removed","path":"inputSchema.properties.regenerate","tool":"generate_character_turn","before":{"type":"boolean","description":"Replace an existing turn animation instead of failing with ANIMATION_EXISTS."},"detail":"Field `regenerate` was removed from `generate_character_turn` input; consumers still sending it may be rejected or silently ignored.","severity":"breaking"},{"kind":"description_changed","tool":"get_character","after":"The full PhaserCharacter JSON: animations, frameSize, gameType, per-group atlas + spritesheet URLs, poses and mount points. The top-level animationQualityGate is the delivery verdict per animation: ready:true means its deliveredIssues list is empty; needs_review means follow its actions before claiming the animation is ready; unscored means inspect the frames because no machine score can certify it. Check collision automatically: while an animation plays use animations[activeName].collisionBody before the character-level collisionBody; while displaying a pose use pose.collisionBody first. Fall back to a bbox only when the resolved body is absent. Bodies are normalized to the FULL untrimmed frameSize — never subtract atlas spriteSourceSize/alpha-trim offsets. Every binary URL is presigned and expires in ~1h — download immediately, never store or commit one. This is the same payload the in-app game preview consumes, so it is always a correct export.","before":"The full PhaserCharacter JSON: animations, frameSize, gameType, per-group atlas + spritesheet URLs, poses and mount points. Check collision automatically: while an animation plays use animations[activeName].collisionBody before the character-level collisionBody; while displaying a pose use pose.collisionBody first. Fall back to a bbox only when the resolved body is absent. Bodies are normalized to the FULL untrimmed frameSize — never subtract atlas spriteSourceSize/alpha-trim offsets. Every binary URL is presigned and expires in ~1h — download immediately, never store or commit one. This is the same payload the in-app game preview consumes, so it is always a correct export.","detail":"Description of `get_character` changed (24% word delta).","severity":"safe","descriptionDelta":0.23529411764705888},{"kind":"description_changed","tool":"get_job","after":"Poll a background job. Every write tool that returns a jobId is polled here. On status:\"error\" the response is enriched with creditsRefunded and retryCost, so you can tell the user exactly what a retry costs. Poll every few seconds — generations routinely take minutes. THIS IS HOW YOU LEARN WHAT A CREATE CALL MADE: characterIds / assetIds list the entities this job produced — ONE normally, FOUR when create_character ran with the 2x2 variation grid — and on status:\"done\" characterPreviews carries a presigned image per character so you can show the user the options and let them pick. IMPORTANT FOR CHARACTER ANIMATION JOBS: status:\"done\" means processing finished, not that the animation is ready. The response carries animationQualityGate.status:\"check_required\" with the affected animationNames; you MUST call get_character and resolve each affected animation until its gate is ready (or report that it needs review). Do not export, sync, or claim completion before this check. queued:true means it has not started yet (waiting for a slot) and has spent nothing. On any TERMINAL status (done or error) the response carries a `credits` block — { charged, refunded, net, balance, spendCapDaily, spentLast24h, capRemaining }. TELL THE USER `credits.net` AND `credits.balance` when the work finishes, in one short line. Report `net`, never your own pre-flight estimate: the two differ routinely — a 2x2 grid is ONE charge for four entities and failed steps are refunded — so quoting the estimate can report a cost that never happened. Do NOT attach a purchase suggestion to a successful generation; only raise buying credits when a call is actually blocked or the balance will not cover what the user asked for next.","before":"Poll a background job. Every write tool that returns a jobId is polled here. On status:\"error\" the response is enriched with creditsRefunded and retryCost, so you can tell the user exactly what a retry costs. Poll every few seconds — generations routinely take minutes. THIS IS HOW YOU LEARN WHAT A CREATE CALL MADE: characterIds / assetIds list the entities this job produced — ONE normally, FOUR when create_character ran with the 2x2 variation grid — and on status:\"done\" characterPreviews carries a presigned image per character so you can show the user the options and let them pick. queued:true means it has not started yet (waiting for a slot) and has spent nothing. On any TERMINAL status (done or error) the response carries a `credits` block — { charged, refunded, net, balance, spendCapDaily, spentLast24h, capRemaining }. TELL THE USER `credits.net` AND `credits.balance` when the work finishes, in one short line. Report `net`, never your own pre-flight estimate: the two differ routinely — a 2x2 grid is ONE charge for four entities and failed steps are refunded — so quoting the estimate can report a cost that never happened. Do NOT attach a purchase suggestion to a successful generation; only raise buying credits when a call is actually blocked or the balance will not cover what the user asked for next.","detail":"Description of `get_job` changed (16% word delta).","severity":"safe","descriptionDelta":0.15923566878980888}],"published_at":"2026-08-20T17:38:37.970Z"}]