Skip to content

First raster write on a fresh safe copy conflicts with its recovery checkpoint #619

Description

@Flow-Fly

Reproduced failure

The first raster proposal on a newly approved safe copy of a blank project fails with revision_conflict and leaves the Creative Run in recovery-required, even though no user or concurrent agent changed the project.

Found during the owner-requested browser playtest after #553 / PR #617. Tested the production build at a5a5869eeca274a09c9864212e5e29ff368fabd3; its tree d77b0ddc8542297f518df66e1c4201aab097e64b equals merged develop commit d6d4042bddba54a050442534c32e97da9d8a8c07.

Reproduced on 2026-09-10 through both public transports:

  • Chrome 152.0.7977.83: window.pixelForgeSiteTools.invoke fallback, native API absent.
  • Canary 155.0.8050.0 with --enable-features=WebMCP: real registered native tools via document.modelContext.executeTool(registeredTool, JSON.stringify(input), { signal }).

The fallback minimal case failed twice without instrumentation. The native minimal case failed with the same outcome. These are local production-build tests with actual UI approvals, real browser storage and canvas, no mocked host/adapter, and no provider calls.

Minimal public reproduction

  1. Open a fresh browser profile on the normal app entry with the initial blank 64 × 64 Untitled project.
  2. Request facade/catalogue 1.0, observations structure, palette, raster, raster writes, two transactions and a 300-second lifetime.
  3. In the actual consent dialog select Untitled, keep the default safe-copy mode, approve the three content categories and sharing, approve Raster Artist Mode, and approve the Brief.
  4. Observe structure at revision 0; observe palette and a 1 × 1 layer raster region at (0, 0) at that revision using the returned layer/frame/cel identities.
  5. Start the run locally.
  6. Propose one raster-patch / project.raster.patch transaction at revision 0, using that observation's digest and an exact existing orange palette entry, with one patch { x: 0, y: 0, width: 1, height: 1, rows: ['A'] }.

Expected: one committed pixel and revision 1.

Actual: { ok: true, result: { type: 'proposal.result', operationId: 'first-raster-write', outcome: 'failed', code: 'revision_conflict' } }. The run enters recovery-required, with zero committed transactions and revision 0. No partial raster write was observed. Local recovery-copy creation and opening work.

Diagnosis

A diagnostic-only browser wrapper around WebCrypto forwarded every digest call unchanged and captured just the raster digest framing on disposable test artwork. The two calls have identical target, revision 0, layer/frame/cel, region, rows ['.'] and empty legend. Only the index representation changes:

  • Observation: indexMeaning: 'rgba8', four trailing pixel bytes.
  • Transaction preflight: indexMeaning: 'palette-index-1-based-transparent-zero', five trailing bytes.

The code path explains that change:

The revision does not change during this derived-state rebuild. A separate end-to-end scenario which changes frame duration first, then freshly observes and draws, succeeds through both transports: exact orange/yellow diamond pixels, idempotent replay, pause, package checksums, revocation, recovery, new approval and local Accept. This establishes that the raster command itself is usable once the first checkpoint has normalized the representation; it is not a proposed user workaround.

Repair criteria to retain

  • The fresh-copy first-raster scenario commits once through the normal entry and real checkpoint boundary, with a red-before/green-after browser regression.
  • Checkpoint capture and subsequent durable recovery must preserve the observation/write contract; do not remove digest checks or weaken concurrent-change protection.
  • Preserve coherent raster/index state, checkpoint restoration, the original project, Undo/Redo, and package/reload behavior. Account for the adjacent stale-index case in Shape gestures leave RGBA and palette indices temporarily inconsistent #519 when choosing serialization behavior.
  • Keep the successful lifecycle scenario green.

This is a confirmed bug record, not a newly approved delivery slice. No production code was edited during this playtest. The eventual fix needs its own bounded delivery handoff; it must not be folded into the already merged PR.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent:completeAgent implementation complete; awaiting merge or final verificationagentic-loopTracked by the reusable agentic loop workflowagentic-taskChild issue intended for agent implementationbugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions