docs: contract completed-frame capture repair and safe self-gate launch

This commit is contained in:
Erik 2026-09-05 11:53:12 +02:00
parent 350340d2ed
commit 6347e0f826
4 changed files with 137 additions and 4 deletions

View file

@ -0,0 +1,92 @@
# #476 — capture the submitted current frame, never uninitialized readback
Lead contract2026-09-05. NOT IMPLEMENTED. Read the full
476-capture-lifetime-diagnosis.md first: it records the lead's production
trace, failed PNG and named-retail/paired-binary screenshot boundary. This
is a modern Vulkan retained-copy lifetime repair, not a new AC algorithm.
## Bounded change
Move the existing IPrivateFrameScreenshot invocation from
PrivatePresentationRenderer's still-open render phase to the outer
RenderFrameOrchestrator's successfully closed frame boundary. The sequence
is resource/world/private drawing, GPU measurement close, ONE GPU frame close,
capture, CPU diagnostics, shadow comparison, lifecycle checkpoint. Keep the
existing immutable outcome fields truthful: ScreenshotCaptured reflects that
post-close capture, while portal/private presentation facts remain those of
the frame just drawn. Wire the same optional capture adapter through
FrameRootComposition; no second frame owner or screenshot queue.
Preserve the existing begin/render/measurement/recovery/close error contract:
Begin failure does not close; every successful Begin attempts exactly one
End, including render/measurement failure; recovery remains before End when
render fails; aggregated errors retain their original ordering. A close
failure must not execute capture/post-close consumers or cause a second End.
Capture/diagnostic/post-diagnostic failure AFTER close must propagate without
trying to close/recover a finished GPU frame. Zero-area input opens nothing,
captures nothing and leaves queued requests for a later renderable frame.
Do not alter the idempotent GpuDeviceFrameLifetime clearing rule.
In VulkanGpuDevice's existing capture fields/methods and EndFrame, ensure
readback is valid only after an actual successful submission containing the
retained image-to-buffer copy. Allocation/resize or command recording alone
is not validity. Prevent an open/unsubmitted frame, missing copy, skipped
acquisition, failed submission or new-size buffer from being advertised as
the newly completed requested frame. Use minimal local state on the existing
owner; reset it at the actual relevant lifetime edges. Preserve the correct
bring-up caller that already reads after frame close. Do not read the
swapchain after present or change semaphore/flight/resource retirement.
Retain opt-in capture and zero copies/allocations when off. Keep the existing
DeviceWaitIdle readback behavior for a valid submitted capture; do not add
waits elsewhere. No sleeps, first-image discard, guessed warmup, retry-until-
pretty loop, shader/quality change or screenshot naming/orientation rewrite.
The controller's one-request-per-frame, complete/failed status and atomic PNG
behavior remain intact. Do not bundle unrelated stale GL comments/cleanup.
## Files and ownership
Scope: RenderFrameOrchestrator, PrivatePresentationRenderer,
FrameRootComposition; capture-only portions of VulkanGpuDevice and its
Resources partial; existing focused orchestrator/private/composition,
screenshot/lifecycle and Vulkan capture tests; relevant architecture paragraph.
No Runtime/world/lighting/mesh/walk edits. Any intentional behavioral deviation
needs its register row in the landing commit; none is expected.
Use a fresh codex/s5-476-openai-impl scratch at the commit containing this
contract. #477 is in a DIFFERENT scratch and touches other portions of the
same Vulkan partials. Do not copy/edit its source. Root integrates narrow
accepted changes and preserves both; do not perform a whole-file overwrite.
No agent commit/graphical launch or extra agents. Both AcDream.App and retail
acclient must be absent before EVERY build/test.
## Proof
Exercise the REAL orchestrator plus real PrivatePresentationRenderer and
FrameScreenshotController composition with a fake GPU/frame whose distinct
frame pixels become readable ONLY at End/submission. Do not merely assert a
manually written phase list. Startup and actual-size-change first captures
must carry the newly submitted pixels, with exact orientation/size. Reuse
existing fake-GPU/test fixtures rather than a new recording framework.
Verify real phase order and every failure boundary above, queued requests,
zero-area then resumed frame, and capture-off behavior. For native validity,
exercise the actual production state transitions/call binding, not an unused
Boolean policy helper. Capture before first submit, after resize before its
first copy, while open and after failed/no-copy submission must not read old
bytes as a valid current frame. Existing bring-up/format tests remain green.
Two actual-production mutations: restore capture before End; then mark the
new buffer/recorded-but-unsubmitted copy as valid. Each must fail its intended
pixel/validity assertion, not compilation or test setup. Restore exact raw
hashes, rebuild Release0W0E and run affected hermetic lanes with zero new skips.
Return commands/TRX/hashes and precise claim boundaries. Root independently
verifies, then sequential behavior/retail and production/lifetime review
lenses follow within the owner's ten-review limit.
Graphical closure only after #477's synchronization run is clean and no agent
is building/testing: fresh Release, ACE9000 up, both clients absent, one
bounded real Vulkan run. Capture first requested frame at startup and across
two REAL different framebuffer sizes, plus a settled portal/world frame.
Preserve every PNG and record PASS/FAIL paths, provisional until owner looks.
This repair alone cannot close #477 or the failed G4 owner matrix.

View file

@ -99,3 +99,36 @@ do not create a global telemetry framework or resurrect camera-flood light
selection. No current PNG/light-membership witness exists for the failed
owner session. If a genuinely required retail fact cannot be recovered
statically, follow the owner's stop rule; do not invent it.
### Lead static follow-up (no lighting repair or live witness)
The lead independently read CellManager::ChangePosition, minimize_envcell_lighting,
DrawEnvCell and SetStaticLightingVertexColors, then checked the paired exe
above using its PE sections. Exact body ranges/hashes:
| VA / bytes | SHA-256 |
| --- | --- |
|004559B0 / 555|DDF73D34A7A8099672191EB5A18A9C21F73D4A3A0B379B94840D709AD6E64D49|
|0054C170 / 58|C948472BF8FE01BD318F4EB2BE0A6FD0FB1D87BE19114F776C613CCE3737250D|
|0059F170 / 293|408D9818DD02750825F36D05824D3562F9BB62D3FEFABF1DD172375A3C6C91B2|
|0059CFE0 / 759|E0148A7FA69A56ED2D4E49201A8284AA5907AE314FF9A8CCC9E77B3FC3DDD340|
The ambient branch loads0079B7FC (raw0039B7FC), bytesCDCC4C3E =0.2f,
and passes whiteFFFFFFFF. Static/dynamic capacity data0081EC94/98 is
40/7 respectively (bytes2800000007000000). DrawEnvCell's0059F1F6
E8E5DDFFFF calls0059CFE0. That routine's static loop increments/compares
against num_static_lights at0059D17E before looping; it does not share an
eight-entry EnvCell selector with the dynamic hardware lights. This confirms
the relevant difference, not its activation in the failed Town Network frame.
Lead also read the current filmic shader and its gamma helpers/default
settings, then independently evaluated its scalar formula with no bloom,
rays or volumetric contribution, saturation/contrast1. At screen center,
display inputs0.20/0.10/0.05 map to approximately0.140/0.052/0.023 under
exposure0.8/fullACES; corner strength0.245 further dims them. These are
formula examples, NOT measured current scene pixels. No parameter is changed.
Before the next unattended run, the existing self-gate runner was narrowly
hardened to refuse either client and explicitly use WindowStyle Hidden.
It already uses a real hidden Vulkan window through exact-framebuffer mode.
No route/rendering behavior, graphics profile or quality was changed.

View file

@ -4706,3 +4706,11 @@ old route labels "Sawato"/"Rynthid" are unreliable identifiers. Evidence and
candidate elevated2D31 complex are in479-rynthid-location-evidence.md. A
read-only object/part trace is in progress; transform cause still unproven.
All #478/#481, #476, exact route, C1c/C2/full-G4 obligations in§49 remain open.
Confirmed #476 capture-before-submit now has its separate bounded contract,
476-completed-frame-capture-contract.md. A fresh scratch may implement it
independently; root must integrate only accepted capture portions alongside
#477, never overwrite its unrelated Vulkan barrier changes. Graphical closure
waits for477 validation and an exclusive no-build/test window. The self-gate
runner now explicitly starts hidden and refuses either graphical client;
PowerShell parse/diff check pass. No rendering policy/quality change.