diff --git a/docs/PROJECT-STRUCTURE.md b/docs/PROJECT-STRUCTURE.md
index fe70fa2..fbd4b23 100644
--- a/docs/PROJECT-STRUCTURE.md
+++ b/docs/PROJECT-STRUCTURE.md
@@ -169,6 +169,9 @@ simple hosts. `engine/Age.Engine/Hosting/IMovieHost.cs` owns ordinary, positione
and modal movie playback contracts. `IHost` inherits all four focused contracts; their required and default
behavior is unchanged. The neutral `engine/Age.Engine/Model/MovieMaskTransitionRequest.cs` record carries movie
mask work between the VM, host, and retained graphics without making `Model` depend on `Hosting`.
+`engine/Age.Engine/Model/RgbaImage.cs` owns the format-independent packed RGBA image transported between SYS4
+decoders, host surfaces, renderers, persistence, and tests; consumers do not depend on `Sys4` merely to exchange
+decoded pixels.
`engine/Age.Engine/Model/GfxState.cs` retains cross-domain retained-graphics coordination.
`engine/Age.Engine/Model/GfxState.Contracts.cs` owns its public render, transition, diagnostic, persistence,
diff --git a/docs/remake-architecture-and-roadmap.md b/docs/remake-architecture-and-roadmap.md
index e6a6c73..979be4e 100644
--- a/docs/remake-architecture-and-roadmap.md
+++ b/docs/remake-architecture-and-roadmap.md
@@ -781,6 +781,11 @@ do not mix mechanical moves with semantic changes.
removing the two now-unused imports eliminates `GfxState`'s reverse dependency on the host namespace. Runtime
validation remains green.
+ The fifth bounded contract slice moved the unchanged, format-independent `RgbaImage` record from the SYS4 AGF
+ decoder file into `Model`. Decoders, renderers, persistence, Godot, tests, and the aggregate host now consume
+ the neutral image contract; image-only format imports were removed while genuine SYS4 consumers retained
+ theirs. Decoder and image behavior remain unchanged, and runtime validation remains green.
+
4. **Make the build graph express source ownership.** Stop linking production `.cs` files from `godot/` and
`tools/movie-corpus-gate/` into `Age.Engine.Tests`. Extract the platform-neutral frontend/movie/diagnostic
code into a small production project referenced by Godot, tests, and the corpus gate. Retain both existing
@@ -1141,8 +1146,8 @@ layer's rendering diverges from ADV; save layout.
## 8. Immediate next step
Continue step 3 of the **codebase consolidation** maintenance slice: clarify runtime contracts without changing
behavior or the aggregate host accepted by the VM. With diagnostic, lifecycle, audio, and movie contracts
-established beneath `IHost` and the movie-mask request now neutral, move the format-independent `RgbaImage` record
-from `Sys4` to `Model` next. Update its consumers without changing the record or decoder behavior, removing the
-aggregate host's image-only dependency on the format namespace before separating larger host domains.
+established beneath `IHost` and shared movie/image transport now neutral, introduce the graphics host contract
+next. Preserve its surface, retained-range presentation, transition, texture, capture/replace, and headless-default
+behavior while leaving the remaining surface request records in place for a separate transport cleanup.
Concrete playthrough blockers may still preempt this bounded maintenance work; the consolidation effort does
not replace Phase B gameplay validation or the open cross-platform gates.
diff --git a/engine/Age.Engine.Tests/AgfDecoderTests.cs b/engine/Age.Engine.Tests/AgfDecoderTests.cs
index af1b6de..8346447 100644
--- a/engine/Age.Engine.Tests/AgfDecoderTests.cs
+++ b/engine/Age.Engine.Tests/AgfDecoderTests.cs
@@ -1,4 +1,5 @@
using System.Buffers.Binary;
+using Age.Engine.Model;
using Age.Engine.Sys4;
namespace Age.Engine.Tests;
diff --git a/engine/Age.Engine.Tests/CurDecoderTests.cs b/engine/Age.Engine.Tests/CurDecoderTests.cs
index ef8f37a..ec0a759 100644
--- a/engine/Age.Engine.Tests/CurDecoderTests.cs
+++ b/engine/Age.Engine.Tests/CurDecoderTests.cs
@@ -1,4 +1,5 @@
using System.Linq;
+using Age.Engine.Model;
using Age.Engine.Sys4;
using Xunit;
diff --git a/engine/Age.Engine.Tests/GlyphMaskCompositorTests.cs b/engine/Age.Engine.Tests/GlyphMaskCompositorTests.cs
index 0f14b71..23fb9e4 100644
--- a/engine/Age.Engine.Tests/GlyphMaskCompositorTests.cs
+++ b/engine/Age.Engine.Tests/GlyphMaskCompositorTests.cs
@@ -1,5 +1,4 @@
using Age.Engine.Model;
-using Age.Engine.Sys4;
using Age.Engine.Text;
public class GlyphMaskCompositorTests
diff --git a/engine/Age.Engine.Tests/MovieCorpusGateTests.cs b/engine/Age.Engine.Tests/MovieCorpusGateTests.cs
index 4dc8745..3e16e72 100644
--- a/engine/Age.Engine.Tests/MovieCorpusGateTests.cs
+++ b/engine/Age.Engine.Tests/MovieCorpusGateTests.cs
@@ -1,3 +1,4 @@
+using Age.Engine.Model;
using Age.Engine.Sys4;
public class MovieCorpusGateTests
diff --git a/engine/Age.Engine.Tests/MovieSurfaceRegistryTests.cs b/engine/Age.Engine.Tests/MovieSurfaceRegistryTests.cs
index f03fac6..72ebc9d 100644
--- a/engine/Age.Engine.Tests/MovieSurfaceRegistryTests.cs
+++ b/engine/Age.Engine.Tests/MovieSurfaceRegistryTests.cs
@@ -1,4 +1,4 @@
-using Age.Engine.Sys4;
+using Age.Engine.Model;
public class MovieSurfaceRegistryTests
{
diff --git a/engine/Age.Engine/Hosting/IHost.cs b/engine/Age.Engine/Hosting/IHost.cs
index 7110403..55f2fd1 100644
--- a/engine/Age.Engine/Hosting/IHost.cs
+++ b/engine/Age.Engine/Hosting/IHost.cs
@@ -1,5 +1,4 @@
using Age.Engine.Model;
-using Age.Engine.Sys4;
namespace Age.Engine.Hosting;
diff --git a/engine/Age.Engine/Model/RgbaImage.cs b/engine/Age.Engine/Model/RgbaImage.cs
new file mode 100644
index 0000000..32247dc
--- /dev/null
+++ b/engine/Age.Engine/Model/RgbaImage.cs
@@ -0,0 +1,4 @@
+namespace Age.Engine.Model;
+
+/// A decoded, tightly packed, top-down RGBA8 image.
+public sealed record RgbaImage(int Width, int Height, byte[] Pixels);
diff --git a/engine/Age.Engine/Persistence/NumberedThumbnailCodec.cs b/engine/Age.Engine/Persistence/NumberedThumbnailCodec.cs
index 5b7b013..ed31ff3 100644
--- a/engine/Age.Engine/Persistence/NumberedThumbnailCodec.cs
+++ b/engine/Age.Engine/Persistence/NumberedThumbnailCodec.cs
@@ -1,5 +1,5 @@
using System.Buffers.Binary;
-using Age.Engine.Sys4;
+using Age.Engine.Model;
namespace Age.Engine.Persistence;
diff --git a/engine/Age.Engine/Sys4/AgfDecoder.cs b/engine/Age.Engine/Sys4/AgfDecoder.cs
index 093aab8..5daa0f6 100644
--- a/engine/Age.Engine/Sys4/AgfDecoder.cs
+++ b/engine/Age.Engine/Sys4/AgfDecoder.cs
@@ -1,10 +1,8 @@
using System.Buffers.Binary;
+using Age.Engine.Model;
namespace Age.Engine.Sys4;
-/// A decoded, tightly packed, top-down RGBA8 image.
-public sealed record RgbaImage(int Width, int Height, byte[] Pixels);
-
///
/// Platform-neutral Eushully AGF decoder. Format algorithm ported from GARbro's MIT-licensed
/// ArcFormats/Eushully/ImageAGF.cs (Copyright (C) 2015 morkt).
diff --git a/engine/Age.Engine/Sys4/CurDecoder.cs b/engine/Age.Engine/Sys4/CurDecoder.cs
index 71b9c71..2d537d7 100644
--- a/engine/Age.Engine/Sys4/CurDecoder.cs
+++ b/engine/Age.Engine/Sys4/CurDecoder.cs
@@ -1,4 +1,5 @@
using System.Buffers.Binary;
+using Age.Engine.Model;
namespace Age.Engine.Sys4;
diff --git a/engine/Age.Engine/Sys4/ResourceMap.cs b/engine/Age.Engine/Sys4/ResourceMap.cs
index ebb622a..13f73a2 100644
--- a/engine/Age.Engine/Sys4/ResourceMap.cs
+++ b/engine/Age.Engine/Sys4/ResourceMap.cs
@@ -1,3 +1,5 @@
+using Age.Engine.Model;
+
namespace Age.Engine.Sys4;
///
diff --git a/engine/Age.Engine/Sys4/RgbaSurfaceOps.cs b/engine/Age.Engine/Sys4/RgbaSurfaceOps.cs
index dd6a0e8..0a453cc 100644
--- a/engine/Age.Engine/Sys4/RgbaSurfaceOps.cs
+++ b/engine/Age.Engine/Sys4/RgbaSurfaceOps.cs
@@ -1,3 +1,5 @@
+using Age.Engine.Model;
+
namespace Age.Engine.Sys4;
/// Platform-neutral mutation helpers for AGE's software-modeled RGBA surfaces.
diff --git a/engine/Age.Engine/Text/AgeGlyphMaskCompositor.cs b/engine/Age.Engine/Text/AgeGlyphMaskCompositor.cs
index af5b4e0..cca250f 100644
--- a/engine/Age.Engine/Text/AgeGlyphMaskCompositor.cs
+++ b/engine/Age.Engine/Text/AgeGlyphMaskCompositor.cs
@@ -1,5 +1,4 @@
using Age.Engine.Model;
-using Age.Engine.Sys4;
namespace Age.Engine.Text;
diff --git a/engine/Age.Engine/Text/ImmediateSurfaceTextRenderer.cs b/engine/Age.Engine/Text/ImmediateSurfaceTextRenderer.cs
index 1be823f..e8ae4c3 100644
--- a/engine/Age.Engine/Text/ImmediateSurfaceTextRenderer.cs
+++ b/engine/Age.Engine/Text/ImmediateSurfaceTextRenderer.cs
@@ -1,6 +1,5 @@
using System.Text;
using Age.Engine.Model;
-using Age.Engine.Sys4;
namespace Age.Engine.Text;
diff --git a/engine/Age.Engine/Text/RetainedGlyphLayoutEngine.cs b/engine/Age.Engine/Text/RetainedGlyphLayoutEngine.cs
index 4bb824e..80040bf 100644
--- a/engine/Age.Engine/Text/RetainedGlyphLayoutEngine.cs
+++ b/engine/Age.Engine/Text/RetainedGlyphLayoutEngine.cs
@@ -1,5 +1,4 @@
using Age.Engine.Model;
-using Age.Engine.Sys4;
namespace Age.Engine.Text;
diff --git a/godot/FfmpegMovieDecoder.cs b/godot/FfmpegMovieDecoder.cs
index 763c50e..c41b324 100644
--- a/godot/FfmpegMovieDecoder.cs
+++ b/godot/FfmpegMovieDecoder.cs
@@ -3,6 +3,7 @@ using System.Diagnostics;
using System.IO;
using System.Collections.Generic;
using System.Threading;
+using Age.Engine.Model;
using Age.Engine.Sys4;
internal interface IMoviePacingClock
diff --git a/godot/FfmpegMovieNative.cs b/godot/FfmpegMovieNative.cs
index bbf3d3e..41ef522 100644
--- a/godot/FfmpegMovieNative.cs
+++ b/godot/FfmpegMovieNative.cs
@@ -1,6 +1,7 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
+using Age.Engine.Model;
using Age.Engine.Sys4;
using Microsoft.Win32.SafeHandles;
diff --git a/godot/GodotAdvHost.AdvText.cs b/godot/GodotAdvHost.AdvText.cs
index 68f177a..dea535a 100644
--- a/godot/GodotAdvHost.AdvText.cs
+++ b/godot/GodotAdvHost.AdvText.cs
@@ -4,7 +4,6 @@ using System.Linq;
using System.Threading;
using Age.Engine.Hosting;
using Age.Engine.Model;
-using Age.Engine.Sys4;
using Age.Engine.Text;
public sealed partial class GodotAdvHost
diff --git a/godot/GpuRetainedRenderer.cs b/godot/GpuRetainedRenderer.cs
index 4f78e81..cceaa5c 100644
--- a/godot/GpuRetainedRenderer.cs
+++ b/godot/GpuRetainedRenderer.cs
@@ -2,7 +2,6 @@ using System;
using System.Collections.Generic;
using Godot;
using Age.Engine.Model;
-using Age.Engine.Sys4;
///
/// Godot-native presentation of AGE's sampled retained objects. Static decoded/color-key variants are
diff --git a/godot/IMovieDecoder.cs b/godot/IMovieDecoder.cs
index 5a6fa1d..5f8ebbd 100644
--- a/godot/IMovieDecoder.cs
+++ b/godot/IMovieDecoder.cs
@@ -1,4 +1,5 @@
using System;
+using Age.Engine.Model;
using Age.Engine.Sys4;
internal readonly record struct MovieAudioInfo(int SampleRate, int Channels);
diff --git a/godot/Main.Compositor.cs b/godot/Main.Compositor.cs
index 7697a85..e67b79c 100644
--- a/godot/Main.Compositor.cs
+++ b/godot/Main.Compositor.cs
@@ -2,7 +2,6 @@ using System.Collections.Generic;
using System.Linq;
using Godot;
using Age.Engine.Model;
-using Age.Engine.Sys4;
public partial class Main
{
diff --git a/godot/MovieSurfaceRegistry.cs b/godot/MovieSurfaceRegistry.cs
index c5b9047..c6c8cee 100644
--- a/godot/MovieSurfaceRegistry.cs
+++ b/godot/MovieSurfaceRegistry.cs
@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using Age.Engine.Sys4;
+using Age.Engine.Model;
internal readonly record struct MovieSurfaceBinding(long PlaybackId, long ResourceId, int SurfaceSlot);
internal sealed record MovieSurfaceFrame(RgbaImage Image, string Name, int AssetId);