{
  "kind": "hwanse-render-pipeline-model-review",
  "status": "field-battle-render-model-grounded",
  "source": [
    "out/directdraw_flow.json",
    "out/map_animation_redraw_consumer_review.json",
    "out/map_animation_draw_tile_transform_review.json",
    "out/battle_effect_object_review.json",
    "out/battle_child_lifecycle_draw_order_review.json",
    "docs/map3_active_object_overlay_notes.md",
    "docs/DIRECTDRAW_NOTES.md"
  ],
  "summary": {
    "displayResolution": "640x480x8",
    "sharedApiSurface": "DirectDraw surface/palette copy path",
    "fieldDrawUnit": "37x21 visible tile grid plus dirty/occlusion buffers",
    "battleDrawUnit": "active object/sprite/effect display objects over battle background",
    "surfaceWrapperTable": "0x0055abd8",
    "directDrawVerifiedCallCount": 25,
    "directDrawTotalCallCount": 25,
    "fieldAnimatedFlag0x40Meaning": "confirmed redraw invalidation consumer; visible frame producer still unbound",
    "fieldDrawTimeTileTransformFound": false,
    "battleHelperCoverage": {
      "helpers": 85,
      "helpersWithSpawnTree": 55,
      "helpersWithMotionStep": 34,
      "totalDirectSpawnEvents": 279
    },
    "colorKeyConclusion": "Transparency must be tracked as draw-call/context state.  A source CNS transparent color alone is not sufficient unless the Blt/BltFast path requests source color key handling."
  },
  "artifactStatuses": [
    {
      "path": "out/directdraw_flow.json",
      "exists": true,
      "kind": null,
      "status": "render-pipeline-grounded"
    },
    {
      "path": "out/map_animation_redraw_consumer_review.json",
      "exists": true,
      "kind": "hwanse-map-animation-redraw-consumer-review",
      "status": "redraw-consumer-grounded-visible-motion-producer-unbound"
    },
    {
      "path": "out/map_animation_draw_tile_transform_review.json",
      "exists": true,
      "kind": "hwanse-map-animation-draw-tile-transform-review",
      "status": "draw-time-tile-transform-negative-for-visible-animation"
    },
    {
      "path": "out/battle_effect_object_review.json",
      "exists": true,
      "kind": "hwanse-battle-effect-object-review",
      "status": "helper-child-spawn-frameScript-anchor-review"
    },
    {
      "path": "out/battle_child_lifecycle_draw_order_review.json",
      "exists": true,
      "kind": "hwanse-battle-child-lifecycle-draw-order-review",
      "status": "static-child-lifecycle-reviewed"
    }
  ],
  "sharedDirectDrawModel": {
    "evidenceStatus": "grounded-call-surface",
    "surfaceWrapperTable": "0x0055abd8",
    "primarySlots": [
      {
        "slot": 0,
        "wrapperGlobalHex": "0x0055abd8",
        "role": "primary/front surface wrapper"
      },
      {
        "slot": 1,
        "wrapperGlobalHex": "0x0055abdc",
        "role": "offscreen/back surface wrapper"
      },
      {
        "slot": 191,
        "wrapperGlobalHex": "0x0055aed4",
        "role": "attached backbuffer wrapper"
      }
    ],
    "confirmedMethods": {
      "SetDisplayMode": "640, 480, 8",
      "CreateSurface": "primary/offscreen/backbuffer wrappers",
      "CreatePalette/SetPalette/SetEntries": "256-entry palette path",
      "Flip/Blt": "fullscreen and copy/windowed presentation paths"
    },
    "boundary": "This proves the Win32/DirectDraw presentation surface, not the full game-engine draw ordering. Field and battle diverge before these DirectDraw calls."
  },
  "fieldPipeline": {
    "evidenceStatus": "tilemap-dirty-render-consumer-grounded",
    "drawUnit": "tile row renderer over 37x21 viewport",
    "globals": {
      "dirtyVisibleGrid": "0x005957d0 + y * 37 + x",
      "liveLayer1Flags": "0x0058d7d0 + index * 2",
      "liveLayer0TileIds": "0x00595af0 + index * 2",
      "viewX": "0x004576dc",
      "viewY": "0x004576de",
      "mapWidth": "0x00595ada"
    },
    "confirmedSteps": [
      {
        "vaHex": "0x00425403",
        "meaning": "37x21 viewport dirty scan wrapper."
      },
      {
        "vaHex": "0x00425494",
        "meaning": "Reads layer1 flags and tests low byte bit 0x40."
      },
      {
        "vaHex": "0x004254a5",
        "meaning": "Marks matching visible dirty cell with bit 0x01."
      },
      {
        "vaHex": "0x00425163",
        "meaning": "Dirty row renderer reads live layer0 tile ids."
      },
      {
        "vaHex": "0x004175d3",
        "meaning": "Packs draw descriptor into temporary object +0x28 and x/y into +0x1c/+0x20."
      },
      {
        "vaHex": "0x004199a0",
        "meaning": "Converts low-word tile/frame index to source rect using wrapper width/height/columns."
      }
    ],
    "wrapperFields": {
      "+0x2e": "sprite/tile cell width",
      "+0x30": "sprite/tile cell height",
      "+0x32": "columns",
      "+0x34": "group table candidate"
    },
    "negativeEvidence": {
      "drawTimeUsesLayer1Flag0x40": false,
      "drawTimeUsesFrameCounter": false,
      "drawTimeUsesPerMapAnimationSequence": false,
      "alternateTileSelectionFoundInRedrawConsumer": false,
      "visibleMotionProducerFoundInRedrawConsumer": false
    },
    "currentConclusion": "Field animation flag 0x40 is a redraw invalidation/input to dirty rendering.  The visible motion source is still not proven in the generic tile converter; if motion is tile-id based, a producer must mutate 0x00595af0 before redraw."
  },
  "battlePipeline": {
    "evidenceStatus": "object-sprite-helper-model-grounded",
    "drawUnit": "active object / battle actor / helper child display object",
    "globalsAndFields": {
      "currentObject": "0x0055a800",
      "surfaceWrapperTable": "0x0055abd8 + slot * 4",
      "object+0x28": "packed draw-source selector; low word frame/source index, high word surface slot",
      "object+0x1c": "projected x, fixed 16.16",
      "object+0x20": "projected y, fixed 16.16",
      "object+0x2c": "draw/object flags candidate; exact bit roles still need focused proof"
    },
    "confirmedSteps": [
      {
        "vaHex": "0x00416ce2",
        "meaning": "Common active-object rect/draw-source path."
      },
      {
        "vaHex": "0x00416ceb..0x00416cf6",
        "meaning": "Uses object+0x28 low word as source rect/frame selector."
      },
      {
        "vaHex": "0x00416cf9..0x00416d07",
        "meaning": "Uses object+0x28 high word as surface slot and indexes 0x0055abd8."
      },
      {
        "vaHex": "0x00416d11..0x00416d3d",
        "meaning": "Uses object+0x1c/+0x20 as projected draw coordinates."
      }
    ],
    "helperEvidence": {
      "helpers": 85,
      "helpersWithDirectFrameScript": 20,
      "helpersWithSpawnTree": 55,
      "helpersWithRandomRange": 38,
      "helpersWithMotionStep": 34,
      "frameScriptSpriteCounts": {
        "0x1a": 186
      },
      "rendererReadinessCounts": {
        "renderer-needs-lifecycle-work": 93
      },
      "drawOrderStatusCounts": {
        "no-direct-child-spawn": 30,
        "same-tick-order-needs-list-order-preserved": 6,
        "tick-order-sufficient": 57
      }
    },
    "currentConclusion": "Battle rendering is not a visible tile grid pass.  It composes a battle background and object/helper frame streams, with source selection routed through object+0x28 and surface wrapper metadata."
  },
  "nextFrontier": [
    {
      "area": "field animation producer",
      "work": "Search for live layer0 0x00595af0 mutation tied to map tick/frame counter, or prove a specialized draw path outside 0x004199a0."
    },
    {
      "area": "wrapper validation",
      "work": "Dump wrapper +0x2e/+0x30/+0x32/+0x34 for loaded CNS slots and compare against the CNS rect/source-rect catalog."
    },
    {
      "area": "draw flags / color key",
      "work": "Decode object+0x2c and Blt/BltFast flag consumers to separate opaque copy, source-color-key copy, and palette/context effects."
    },
    {
      "area": "battle object placement",
      "work": "Keep battle actor/helper position opcodes separate from field tilemap placement; do not reuse map_*3 assumptions for battle effects."
    }
  ]
}
