diff --git a/docs/BACKLOG.md b/docs/BACKLOG.md index 45d86d4b..098f1014 100644 --- a/docs/BACKLOG.md +++ b/docs/BACKLOG.md @@ -12,19 +12,28 @@ Specifications and acceptance: [resumed reliability work](reference/resumed-reli | 2 | Await reproduction | #1171 | Bounded SDK response evidence and live comparisons complete; #1174 merged after all 17 checks. Original downward transition remains unreproduced; later startup ramp is retained separately. | Diagnostic slice complete within allocation | Requires recurrence or controlled sender/account changes for causal closure | | 3 | Done | #1172 | Single multiview placeholder; 1981 shell tests, negative/fixed compiled captures and all 17 hosted checks passed; #1175 merged. | Within the 45 min allocation | CI completed alongside live geometry work | | 4 | Done | #919 | #1176 merged after 1991 shell tests, ten failing old-workspace assertions, passing compiled lifecycle checks and all 17 hosted checks. | Within 75 min active upper range including clean-publish recovery | Hosted runner shortage retried with retained evidence; prior Mac performance failure remains #1178 | -| 5 | Done slice / qualification pending | #1177 | Ownership repair #1179 merged. Negative control, 2082 native cases, four CTest suites and all 17 hosted checks passed. Anchored Program interval and eight ISO pixel identities passed; live feeds ended halfway through. [Spec](reference/program-iso-deadline-1177.md). | Attribution/repair slice complete | Full-length local workload still required; retain whole-file Program tail repeat and #1183 departure extension | +| 5 | Done slice / qualification pending | #1177 | Ownership repair #1179 merged. Negative control, 2082 native cases, four CTest suites and all 17 hosted checks passed. The corrected 1800.86-second synthetic Program/eight ISO/SRT identity comparison passes after #1186/#1188/#1189. [Spec](reference/program-iso-deadline-1177.md). | Attribution/repair slice complete | Real SDK, registered camera and bounded end-to-end latency remain unverified; earlier failures retained | | 6 | Await gate | #1074 | Actual D3D11 picture fixture and 39 Tiles regressions pass; disabling black painting fails the pixel assertion. #1180 merge held on the actual Mac command p99 failure tracked in #1178. | About 15 min active qualification work | No retry-until-green; remote interruption/owner policy acceptance remain separate | | 7 | Done | #903 | #1181 merged after real endpoint evidence, 2090 native cases and 17 hosted checks. | Within allocation | Original unexplained audible event remains separate | | 8 | Conditional | #443 / #989 / #1056 | Matched camera/readiness preflight then full output test if prerequisites are met. Preserve failures and NOT JUDGED dependencies. | 60 min, range 45–90 | 30 min measured run plus decode; camera identity/elevation prerequisite | -| 9 | Await hosted evidence | #1178 | Recurrent Mac command p99 failure blocks #1180. Bounded command/reader timing is in #1182 for one instrumented hosted sample. [Spec](reference/mac-command-attribution-1178.md). | Initial attribution slice implemented | Keep 100 ms gate and all repeat outcomes; local controlled transport checks follow the recording | +| 9 | Now | #1178 | Recurrent Mac command p99 failure blocks #1180. Bounded command/reader timing is in #1182 for one instrumented hosted sample. [Spec](reference/mac-command-attribution-1178.md). | Additional native phase attribution: 30 min, range 20–45 | Keep 100 ms gate and all repeat outcomes; local controlled transport checks follow the recording | | 10 | Done | #1183 | #1184 merged: all eight ISO counters stopped after departure while Program advanced 1200 pictures; files readable. | Within allocation | Overall rehearsal failed separately on #1186/#1188 and dual source epochs | | 11 | Done slice / qualification pending | #882 | Compiled Sources lifecycle passes, wrong-pixel publication fails, restored fixture passes. PR #1185 merged after all 17 checks. | Within 90 min upper range | Sampled evidence does not prove every transitional frame | -| 12 | Await gate | #1186 | Preserve final Program picture once while retaining audio tail. [Spec](reference/program-recording-tail-1186.md). | 60 min, range 45–90 | Decoded negative controls fail; full suite and packaged check pending | -| 13 | Await gate | #1188 | Preserve the recording take when sources depart and streaming stops. [Spec](reference/recording-source-loss-1188.md). | 60 min, range 45–90 | Short packaged causal sequence and finalized file checks | -| 14 | Await gate | #1189 | Bind each ISO reader to its actual camera UUID; reproduce duplicate reads through auto/share aliases. [Spec](reference/iso-reader-owner-1189.md). | 45 min, range 30–75 | Native causal regression and corrected local trace/file workload | +| 12 | Done | #1186 | #1187 merged; whole packaged Program file passes 110536 identities with zero duplicate final picture in the 30-minute rehearsal. [Spec](reference/program-recording-tail-1186.md). | Within allocation | All 17 exact-head hosted checks passed; issue closed with retained negative and final-file evidence | +| 13 | Done | #1188 | #1190 merged; original session survives stream-first stop after departure; nine files finalize in one take in short and 30-minute runs. [Spec](reference/recording-source-loss-1188.md). | About 25 min investigation/implementation plus shared packaged validation | All 17 exact-head checks passed; issue closed with exact-session evidence | +| 14 | Done | #1189 | #1191 merged; old consumer fails, 2095 native cases pass, and all eight ISO identity judgments pass across 1800.86 seconds with auto-subscribe enabled. [Spec](reference/iso-reader-owner-1189.md). | About 15 min implementation plus 10 min native suite and shared packaged validation | All 17 exact-head checks passed; issue closed with single-epoch arrival/file evidence | +| 15 | Await #867 | #941 | Stop scheduled Program delivery at explicit teardown without hiding active-output failures. [Spec](reference/program-shutdown-941.md). | 45 min, range 30–75 | Prior head passed all 17 checks; integration hit the existing background-decoder readiness assertion on Metal. Preserve the failure and qualify the repair; excluded from frozen beta | +| 16 | Now | #867 | Prove the background transport can be logically Live before its asynchronous decoder is constructed; wait for actual first-picture readiness before the existing strict single-decoder assertion. [Spec](reference/background-decoder-readiness-867.md). | 20 min, range 15–35 | Controlled delayed-worker proof, old-precondition negative control, focused native tests and exact-head hosted gates; keep beta files frozen | +| Unranked | Intake | #1194 | Two-frame internal Program startup records one Unavailable slot at sequence 2 before the measurement baseline; the whole-trace failure is retained. | Not allocated | No causal old-code comparison; distinct from #941 shutdown and outside the frozen beta | + +12:55 reforecast: 2h41 remain. Local test beta 8c8e15b1qa has been handed to the owner after a 60.1005536-second eight-source Program/ISO/SRT regression and exact-session finalization. All eleven decoded judgments pass; this is not the 30-minute RC gate. The public beta still needs merges, exact main identity and hosted installer qualification. Keep its contents fixed. Use independent capacity for #941 while preserving the owner's local test session; replenish again when that slice finishes. 12:22 reforecast: 3h14 remain. Monitor and departure repairs merged. Use freed capacity for the observed empty-take failure, finish Sources/final-picture acceptance, and preserve time for corrected integrated checks. The Mac diagnostic sample passed but did not explain the earlier failure; #1074 remains held. Replenish again if these slices finish early. +13:55 reforecast: 1h41 remain in the window. #1186 and #1189 repairs are merged after exact-head gates; #1188 is validating their integration. The immutable 30-minute Program/eight ISO/SRT comparison ends about 14:04, then finalize, restore settings and decode every output. Reserve 60–90 minutes for clean public-beta building, final main checks and installer qualification, overlapping independent hosted work. #941 passed 2099 native cases and isolated close traces; its Mac job had a zero-step runner-acquisition cancellation, retained and retried. #1178 adds native phase evidence with unchanged latency limits; its controlled timing tests now pass in hosted CI, while native/hosted causal evidence remains pending. No builds or probes overlap collection; no camera/real-SDK/receiver-latency qualification is inferred. Replenish validation work as capacity frees, keeping the testing beta frozen. + +14:23 reforecast: approximately 73 minutes remain. All three recording repairs are merged and closed with the complete 1800.86-second synthetic comparison; all eleven decoded judgments pass. Public beta source is frozen at 74495ade, with a clean self-contained shell publish/runtime probe passed and the production native suite running. Reserve the next 35–55 minutes for packaging, exact-main CI and hosted install/probe/uninstall of immutable draft assets. The public beta is not yet published. Keep #941/#1178 out; reconcile their branches locally while release gates run, then replenish follow-up validation without changing the frozen release. Superseded CI runs are retained and cancelled to free runner capacity; no failing performance result is discarded or retried until green. + Allocation baseline: 20 min baseline/planning, 120 Auto, 90 resolution, 45 empty-state, 45 teardown, 60 Tiles, 60 conditional output work, 40 validation/report/replenishment reserve = 480 min. These are adjustable allocations, not permission to stop after one fixed list. Use blocked conditional time for the next actionable issue. Owner-deferred #513, business/credential acquisition, public-provider posting and speculative feature expansion are not silently resumed. 09:03 reforecast: roughly 6h33 remain. The new recorded output failure #1177 takes the freed #1172 slot under the owner's replenishment instruction. Allocate up to 150 minutes to attribution/fix/validation before reforecast, with #919 hosted work overlapping; reuse remaining capacity for the next unblocked reserve. No full-output pass is claimed from stable input geometry or successful writer startup. @@ -614,7 +623,7 @@ These can preempt Next on a show night. They do not jump the ranked Now item unt | [#804](https://github.com/iamfatness/CoreVideoPro/issues/804) | #517 measured follow-on: GPU-ready Program packets expired during scheduled shell/multiview export calls (16.6–19.4 ms); retained losses fail release qualification. Owner-promoted repair merged in [#809](https://github.com/iamfatness/CoreVideoPro/pull/809); six matched trials and full native/CI pass. Receiver/display, installed/fleet and lifecycle qualification remain. Remaining #802 work resumes. | | [#811](https://github.com/iamfatness/CoreVideoPro/issues/811) | Physical native MF HD60 S+ reconnect negotiated 1080p60, then failed before new frames with 0x8007001F during #802 qualification. The same failure reproduces with preparation off in both the candidate and installed October 5 beta. Initial capture passed; failures are retained. Attribution remains open. Unranked; does not independently preempt #802. | | [#807](https://github.com/iamfatness/CoreVideoPro/issues/807) | macOS Metal full native CI suite segfaulted on #806 after focused checks passed. Attribution unconfirmed; retain the failed trial, identify the test/stack and verify exact-head CI. Unranked; does not replace approved #802 work. | -| [#782](https://github.com/iamfatness/CoreVideoPro/issues/782) | Windows supervisor disposal queried an already-disposed Process in the crash lock-order CI test. Captured stack and run; attribution and focused fix need owner rank. **2026-10-25 (CI sweep A):** the exception that failed the run is fixed in the sweep-A PR: `DisposeChild` called `Process.HasExited` on a Process that never associated (a failed `Process.Start` leaves it in `_process`; a disposed one behaves the same), which threw out of `Stop`/`DisposeAsync`. That exception was the mask, not the cause: it hid an earlier failure of the lock-order test, presumed to be its 10 s `concurrentSync` wait timing out under thread-pool starvation on the hosted runner (unproven). The test's two workers now run on dedicated threads; three regression tests cover the disposal path. Keep open until a hosted run confirms. | +| [#782](https://github.com/iamfatness/CoreVideoPro/issues/782) | Windows supervisor disposal queried an already-disposed Process in the crash lock-order CI test. Captured stack and run; attribution and focused fix need owner rank. **2026-10-25 (CI sweep A):** the exception that failed the run is fixed in the sweep-A PR: `DisposeChild` called `Process.HasExited` on a Process that never associated (a failed `Process.Start` leaves it in `_process`; a disposed one behaves the same), which threw out of `Stop`/`DisposeAsync`. That exception was the mask, not the cause: it hid an earlier failure of the lock-order test, presumed to be its 10 s `concurrentSync` wait timing out under thread-pool starvation on the hosted runner (unproven). The test's two workers now run on dedicated threads; three regression tests cover the disposal path. 2026-11-06: closed after inspecting all five actual crash-lock/disposal results in the Windows TRX from run 42262314135; every case passed. The presumed masked-timeout cause remains unproven. | | [#784](https://github.com/iamfatness/CoreVideoPro/issues/784) | Screen/window capture flashes after asynchronous WGC lifecycle change: the shell rejects connecting and auto-retries, repeatedly restarting sessions. Fixed in merged #785 and beta `beta-2026-10-04-92e6b1e`: accepted pending requests are preserved and repeated connect is idempotent. Owner visual check was positive; installed capture alongside streaming acceptance remains. | | [#735](https://github.com/iamfatness/CoreVideoPro/issues/735) | Fixed: the CPU-fallback stream path delivered nothing from 2026-09-30 because shared-AAC routing withheld PCM from a sender that was not on the GPU path. Remaining: RTMP was not tested separately from SRT; owner acceptance on a machine without a hardware encoder. | | [#701](https://github.com/iamfatness/CoreVideoPro/issues/701) | Media playout video can stutter or freeze during a live show; identify decoder versus presentation. Had no row until the 2026-10-02 review. | @@ -807,7 +816,7 @@ Owner closes each issue. Outcome per issue: fixed, no-repro (with hardening), ma | Issue | Outcome | Evidence | |---|---|---| | [#850](https://github.com/iamfatness/CoreVideoPro/issues/850) | mac-unverified, hardened | macOS-only failure; test now judges healthy phases against a 60 s window and shortens it to 60 ms only for the decay phase. 25/25 Windows runs before and after. | -| [#867](https://github.com/iamfatness/CoreVideoPro/issues/867) | no-repro, diagnostics added | 25/25 before; failing line was the process-global decoder-created count. Failure message now names restarts and frame ids. | +| [#867](https://github.com/iamfatness/CoreVideoPro/issues/867) | Active window, readiness repair | November 6 Metal recurrence retained. #1193 adds controlled delayed-construction evidence, actual-picture readiness and the observed count; historical trials still omit the count. | | [#877](https://github.com/iamfatness/CoreVideoPro/issues/877) | fixed | utf-8 pinned in monitor_evidence.Core; new test fails before, passes after. | | [#878](https://github.com/iamfatness/CoreVideoPro/issues/878) | no-repro (fixed on main by #875) | WgcScreenCapture UTF-8 title test passes. | | [#881](https://github.com/iamfatness/CoreVideoPro/issues/881) | fixed | Reproduced with a held reader (the concurrent-reader test is a stress guard); store now serialises, retries, replaces atomically and never persists a fabricated Enabled=false. | diff --git a/docs/reference/background-decoder-readiness-867.md b/docs/reference/background-decoder-readiness-867.md new file mode 100644 index 00000000..b8621fe1 --- /dev/null +++ b/docs/reference/background-decoder-readiness-867.md @@ -0,0 +1,9 @@ +# Background decoder readiness in the transport regression — #867 + +The background-only transport refusal regression waits for logical `live` state, then asserts one decoder was created. `MediaTransports` publishes that state before its asynchronous worker constructs the decoder. The retained November 6 Metal failure on #1192 repeats this assertion at line 9682, reporting no background pictures or restarts but omitting the actual created count. Earlier failures remain retained; their missing count prevents attributing each one to the same initiating condition. + +Use the real MediaCore/MediaTransports consumer with an injected factory whose construction is held behind a bounded test gate. Demonstrate that the source is logically Live while the constructor count is still zero, then release the worker and observe an actual first picture. This establishes the missing readiness guarantee without changing production scheduling or weakening the strict one-decoder assertion. + +The existing refusal test must wait for both Live and a real background picture before exercising pause/play. Preserve refusal reasons, unchanged transport state, unknown-asset diagnostics and the final exact constructor count. Include the observed count in failure output. A missing decoder must still fail its bounded readiness wait; duplicate construction must still fail the exact-count assertion. + +Implementation sequence: retain the hosted failure; add the controlled readiness regression and repair the existing wait; compile the actual native test executable; run a control that applies the old one-decoder expectation while construction is held, restore and run both focused cases plus the related MediaCore command regressions; submit for hosted Windows/Metal/stub checks. No arbitrary increase to performance limits, no retry-until-green and no production adapter change. Keep this test repair outside the frozen Windows beta; #941 remains held until its integrated checks pass. diff --git a/native/tests/MediaCoreCommandTest.cpp b/native/tests/MediaCoreCommandTest.cpp index 76945a32..ee097975 100644 --- a/native/tests/MediaCoreCommandTest.cpp +++ b/native/tests/MediaCoreCommandTest.cpp @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -9643,6 +9644,40 @@ TEST(MediaCoreCommand, AGenuinelyUnroutedClipIsStillReleasedAfterTheGrace) { // `media:` row, so the refusal comes from the LAST tier - and it must carry a // real reason naming the loop, never silently do nothing. // --------------------------------------------------------------------------- +TEST(MediaCoreCommand, BackgroundTransportCanBeLiveBeforeDecoderConstruction) { + auto modules = corevideo::modules::createStubModules(); + CountingDecoder::resetAll(); + std::mutex factoryMutex; + std::condition_variable factoryReady; + bool releaseFactory = false; + modules.mediaDecoderFactory = [&]() -> std::unique_ptr { + std::unique_lock lock(factoryMutex); + // A failed assertion must not leave teardown waiting on an unbounded gate. + if (!factoryReady.wait_for(lock, std::chrono::seconds(3), [&] { return releaseFactory; })) return {}; + lock.unlock(); + return std::make_unique(); + }; + corevideo::core::MediaCore core(std::move(modules)); + core.enableAudioOutputWorker(); + (void)core.applyCommands(corevideo::rpc::Json::Array{ + slice3bBackgroundScene("scene-a", "load-scene-graph")}); + ASSERT_TRUE(slice3bPumpUntil(core, [&] { + return slice3bTransportState(core, "background:bg") == "live"; + })); + // #867: the old readiness predicate is true while construction is held. + EXPECT_EQ(CountingDecoder::created.load(), 0) + << "logical Live is not decoder readiness; created=" << CountingDecoder::created.load(); + { + std::lock_guard lock(factoryMutex); + releaseFactory = true; + } + factoryReady.notify_all(); + ASSERT_TRUE(slice3bPumpUntil(core, [&] { + return CountingDecoder::lastFrameIdFor("background:bg") > 0; + })) << "the released background decoder never produced its first picture"; + EXPECT_EQ(CountingDecoder::created.load(), 1); +} + TEST(MediaCoreCommand, ATransportOnABackgroundOnlyAssetIsRefusedAndNamesTheLoop) { auto modules = corevideo::modules::createStubModules(); CountingDecoder::resetAll(); @@ -9653,8 +9688,9 @@ TEST(MediaCoreCommand, ATransportOnABackgroundOnlyAssetIsRefusedAndNamesTheLoop) (void)core.applyCommands(corevideo::rpc::Json::Array{ slice3bBackgroundScene("scene-a", "load-scene-graph")}); ASSERT_TRUE(slice3bPumpUntil(core, [&] { - return slice3bTransportState(core, "background:bg") == "live"; - })) << "the loop background never went live"; + return slice3bTransportState(core, "background:bg") == "live" && + CountingDecoder::lastFrameIdFor("background:bg") > 0; + })) << "the live loop background never produced its first picture; created=" << CountingDecoder::created.load(); ASSERT_EQ(slice3bMediaSource(core.sessionState(), "media:bg"), nullptr) << "this asset must exist ONLY as background:bg for the test to exercise the last tier"; @@ -9680,7 +9716,8 @@ TEST(MediaCoreCommand, ATransportOnABackgroundOnlyAssetIsRefusedAndNamesTheLoop) // #867: this counter is process-global. If it ever reads 2 again, say WHICH source // restarted (loop restart vs a decoder opened outside this core) instead of a bare 2 vs 1. EXPECT_EQ(CountingDecoder::created.load(), 1) - << "background:bg decoder restarts=" << CountingDecoder::restartsFor("background:bg") + << "background:bg decoders created=" << CountingDecoder::created.load() + << " restarts=" << CountingDecoder::restartsFor("background:bg") << " first-frame-id-after-restart=" << CountingDecoder::firstFrameIdAfterRestartFor("background:bg") << " last-frame-id=" << CountingDecoder::lastFrameIdFor("background:bg"); }