Black-stream fixes: CCD restore snapshot pruning, iOS silent-black recovery, devnode journal retention #175

Merged
enricobuehler merged 3 commits from worktree-black-stream-fixes into main 2026-08-12 13:11:33 +00:00
Owner

Three field bugs from the 2026-08-12 reports (AORUS RX 9070 XT + iOS; a second Windows+Android host), one commit each:

1. fix(win-display): prune unplugged targets from the CCD restore snapshot. A monitor unplugged mid-session left teardown replaying a snapshot whose paths reference an absent target — SetDisplayConfig rejects the WHOLE array with 0x57 ERROR_INVALID_PARAMETER, nothing restores, and the next session snapshots the wreckage (the poisoned-snapshot chain; field: rc=0x57 after a mid-session unplug, then sessions flipping black/working at random, incl. one that genuinely encoded a black opening frame). The restore now prunes against a live QDC_ALL_PATHS sweep: stale paths drop, the mode table is rebuilt with indices remapped (an orphaned mode entry is itself an 0x57), an empty survivor set skips the apply so the dark-desk backstop decides. Verbatim behavior when everything is attached or the availability query fails. 5 new unit tests over the pure remap (drop-with-modes, clone-shared mode dedup, sentinel/corrupt indices, cross-adapter aliasing).

2. fix(apple): never sit black AND silent while the video format is unseeded. Both iOS pumps dropped every AU in a silent guard while format == nil (opening IDR's parameter sets lost or unparsed) — no request, no log, forever; under the infinite GOP nothing re-delivers parameter sets unless the client asks. Field signature: black stream, client decoding nothing and requesting nothing, host streaming perfectly, "randomly" self-healing when a later event produced an IDR. The pumps now set awaitingIDR (through the existing 100 ms-throttled recovery request) and log once.

3. fix(win-display): a failed devnode re-enable must keep its crash-journal entry. enable_instances cleared every requested id from the pnp_disable_monitors journal even when the re-enable FAILED — erasing the only retry record, so neither the running host nor the next start would recover, leaving the operator's monitor invisible to Windows and every display listing (the Android-host "displays gone until full restart" report). Only successfully re-enabled ids clear now; failures stay journaled and log the consequence.

Validation: pf-win-display 11/11 tests + clippy -D warnings on native Windows (.173); Swift package builds clean against a fresh xcframework (Build complete).

Three field bugs from the 2026-08-12 reports (AORUS RX 9070 XT + iOS; a second Windows+Android host), one commit each: **1. `fix(win-display): prune unplugged targets from the CCD restore snapshot.`** A monitor unplugged mid-session left teardown replaying a snapshot whose paths reference an absent target — `SetDisplayConfig` rejects the WHOLE array with `0x57 ERROR_INVALID_PARAMETER`, nothing restores, and the next session snapshots the wreckage (the poisoned-snapshot chain; field: `rc=0x57` after a mid-session unplug, then sessions flipping black/working at random, incl. one that genuinely encoded a black opening frame). The restore now prunes against a live `QDC_ALL_PATHS` sweep: stale paths drop, the mode table is rebuilt with indices remapped (an orphaned mode entry is itself an 0x57), an empty survivor set skips the apply so the dark-desk backstop decides. Verbatim behavior when everything is attached or the availability query fails. 5 new unit tests over the pure remap (drop-with-modes, clone-shared mode dedup, sentinel/corrupt indices, cross-adapter aliasing). **2. `fix(apple): never sit black AND silent while the video format is unseeded.`** Both iOS pumps dropped every AU in a silent guard while `format == nil` (opening IDR's parameter sets lost or unparsed) — no request, no log, forever; under the infinite GOP nothing re-delivers parameter sets unless the client asks. Field signature: black stream, client decoding nothing and requesting nothing, host streaming perfectly, "randomly" self-healing when a later event produced an IDR. The pumps now set `awaitingIDR` (through the existing 100 ms-throttled recovery request) and log once. **3. `fix(win-display): a failed devnode re-enable must keep its crash-journal entry.`** `enable_instances` cleared every requested id from the `pnp_disable_monitors` journal even when the re-enable FAILED — erasing the only retry record, so neither the running host nor the next start would recover, leaving the operator's monitor invisible to Windows and every display listing (the Android-host "displays gone until full restart" report). Only successfully re-enabled ids clear now; failures stay journaled and log the consequence. **Validation:** pf-win-display 11/11 tests + clippy `-D warnings` on native Windows (.173); Swift package builds clean against a fresh xcframework (`Build complete`).
enricobuehler added 3 commits 2026-08-12 13:09:02 +00:00
A monitor unplugged mid-session left the teardown replaying a snapshot whose
paths reference an absent target — SetDisplayConfig rejects the WHOLE array
with 0x57 ERROR_INVALID_PARAMETER, nothing restores, the desk stays dark, and
the next session snapshots the wreckage (the poisoned-snapshot chain; field
2026-08-12: rc=0x57 across a mid-session unplug, then sessions flipping
between black and working at random, incl. one that genuinely encoded black).

The restore now prunes the snapshot against a live QDC_ALL_PATHS availability
sweep before replaying: stale paths drop, the mode table is rebuilt with only
the entries the survivors reference (an orphaned mode entry is itself an
0x57), and an empty survivor set skips the apply so the dark-desk backstop
decides. Verbatim behavior is unchanged when everything is still attached or
when the availability query itself fails.
Both pumps (Stage2Pipeline + the stage-1 StreamPump) dropped every AU in a
silent guard while 'format' was nil — the opening IDR's parameter sets never
arrived or never parsed, and under the host's infinite GOP nothing re-delivers
them unless the client asks. Field 2026-08-12 (iOS, H265): sessions decoding
nothing, requesting nothing, host streaming perfectly — a black stream with
zero recovery requests, randomly self-healing only when some later event
produced a fresh IDR.

While format is nil after the first received AU, the pumps now set awaitingIDR
(routing through the existing 100 ms-throttled recovery.request()) and log the
state once, so a lost/unparsed opening IDR converts to a normal recovery
round-trip instead of a permanent silent black.
fix(win-display): a failed devnode re-enable must keep its crash-journal entry
ci / rust-arm64 (pull_request) Successful in 1m36s
ci / docs-site (pull_request) Successful in 1m22s
apple / swift (pull_request) Successful in 1m43s
apple / screenshots (pull_request) Skipped
ci / bun-nix (pull_request) Successful in 3m34s
ci / web (pull_request) Successful in 4m2s
android / android (pull_request) Successful in 4m13s
ci / rust (pull_request) Successful in 5m56s
712ee935d6
enable_instances cleared every requested id from the pnp-disabled-monitors
journal unconditionally — a mid-life re-enable failure erased its own
crash-recovery entry, so neither the running host nor the next start would
ever retry, leaving the operator's monitor disabled (invisible to Windows and
every display listing) until a manual Device Manager fix. Field 2026-08-12
(Android-client host running the pnp_disable_monitors axis): displays gone
from the client after 2-3 sessions, only a full host restart bringing them
back — the restart path only works while the journal still has the entry.

Only successfully re-enabled ids clear now; failures stay journaled (and are
logged with the consequence) so startup_recover retries them.
enricobuehler merged commit 23f9b1130e into main 2026-08-12 13:11:33 +00:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: unom/punktfunk#175