# MOB1 verification Branch `fix/mobile-view-blank`. Baseline `ad5f8cd7`. Failing regression commit `c240598a`. Fix commit `76e93fa4`. ## Reproduction and cause The baseline ran in this worktree's isolated Obsidian 1.14.4 on Linux. Phone emulation used 390 by 844 pixels, deviceScaleFactor 1, `mobile: true`, and matching screen dimensions before `dev:mobile on`. No physical iOS device was used. A `podcast_player_view` leaf was saved in the collapsed right sidebar. After a renderer reload, the leaf was deferred. A touch swipe from (385, 400) to (85, 400) opened the drawer. The actual drawer picker and its **Podcast Player** option were clicked. The leaf became non-deferred and visible, but `contentEl.innerHTML` remained empty and `shouldMountPodcastView()` was false. `before.png` captures the blank view. `after.png` shows the Library through the same path. The committed journey seeds **Sidebar Podcast**, served from a test-local `http://podnotes.test:/sidebar-podcast/feed.xml`, and asserts the Library and podcast card after the picker selection. It does not call PodNotes' activation method to reveal the leaf. Historical sources: - https://github.com/chhoumann/PodNotes/pull/208 - https://github.com/chhoumann/PodNotes/issues/110 - https://github.com/chhoumann/PodNotes/pull/401 - https://github.com/chhoumann/PodNotes/issues/505 PR #208 mitigated a suspected iOS restart loop reported on Obsidian 1.6.7, with duplicate Podcast Player entries. It deferred mobile auto-opening and restored-view mounting. It did not reproduce the original iOS crash. The plugin's minimum Obsidian version was then 0.15.9, so deferred views, introduced in 1.7.2, were unavailable on some supported versions. The current minimum is 1.13.0. The real 1.14.4 run confirms that Obsidian already keeps a hidden restored leaf deferred. PR #401 moved playback out of the view. Fresh-install-only auto-opening and leaf deduplication remain intact. ## Red, green and mutation `TMPDIR=/data/home/tmp/podnotes-MOB1 fnm exec --using 22 -- npm run test:e2e -- -t 'restored phone sidebar'` Baseline `red.log`: ``` WaitForTimeoutError: Timed out waiting for Library page shown after 15000ms. Tests 1 failed | 241 skipped (242) ``` Fixed `green.log`: ``` Tests 1 passed | 241 skipped (242) ``` `mutate.mjs` temporarily moves MainView's open behavior into `mountFromCommand()` and calls it only after `activateView()` reveals the leaf. It builds that source, restores the source, runs the committed journey against the mutant bundle, and restores the fixed bundle. The plausible wrong fix fails with the same Library timeout in `mutant.log`. It does not merely revert the original patch. ## Startup No measurable slowdown. The first five-load pilot showed a gap, but the larger comparison changed direction when the order changed. Combined medians are effectively equal. This is measurement variability, not evidence of added plugin work. `drive.mjs` alternates the baseline and fixed production bundles in one isolated Obsidian 1.14.4 process at 390 by 844 pixels. It measures the **Startup time** report for warm renderer reloads, not cold process launches. PodNotes is the only active community plugin. Each run uses the same saved library, hidden right-sidebar leaf and playback state for both builds. It verifies the loaded build through the removed gate method. One warmup per build is excluded. The first run contains 20 baseline-first pairs. The repeat contains 20 fixed-first pairs. The table combines all 40 measured loads per build. The host has 12 available cores. Load averages were 5.55 / 3.52 / 2.49 after the first run and 2.60 / 3.22 / 2.50 after the repeat. Other sessions share this host. | Measurement | Baseline median | Fixed median | Baseline middle 50% | Fixed middle 50% | Baseline min to max | Fixed min to max | | --- | ---: | ---: | --- | --- | --- | --- | | Community plugin load | 8.10 ms | 8.05 ms | 5.18 to 10.53 ms | 6.18 to 10.88 ms | 4.2 to 31.1 ms | 4.5 to 15.7 ms | | Total app startup | 92.10 ms | 92.05 ms | 89.53 to 94.95 ms | 85.83 to 100.05 ms | 81.8 to 162.0 ms | 78.6 to 181.5 ms | The baseline-first run's plugin medians were 7.00 and 9.85 ms. The fixed-first repeat's medians were 8.85 and 6.65 ms. The pooled paired difference had a median of +0.25 ms, with 22 of 40 fixed loads slower. This does not support a consistent penalty from the fix. No speedup is claimed. All 80 measured loads had one deferred leaf, no mounted PodNotes view, zero fixture-feed requests, one plugin-owned media element and a live API. No runtime errors were captured. Raw results are in `startup.json`, `startup-reverse.json` and `startup-combined.json`, with summaries from `summarize-startup.mjs`. A separate diagnostic run used `loader-probe.js`, injected through a persistent CDP connection to this same isolated app. It measured code evaluation, module execution, `onload()`, `loadSettings()`, and `loadCSS()`, and counted view factory calls. Three measured loads per build showed zero view constructions and no runtime errors. Median `onload()` was 4.2 ms before and 4.0 ms after, including 1.6 ms for settings in both. Code evaluation was 8.9 and 8.8 ms, and module execution was 1.1 and 1.0 ms. The debugger and wrappers changed the timings, so these diagnostic samples are excluded from the comparison above. They show no extra initialization or view work to remove. See `profile.json` and `profile-summary.json`. Re-run the measurements after starting this checkout's isolated 1.14.4 instance: ```sh TMPDIR=/data/home/tmp/podnotes-MOB1 fnm exec --using 22 -- node --experimental-strip-types .obsidian-e2e-artifacts/MOB1/drive.mjs TMPDIR=/data/home/tmp/podnotes-MOB1 MOB1_REVERSE=1 fnm exec --using 22 -- node --experimental-strip-types .obsidian-e2e-artifacts/MOB1/drive.mjs TMPDIR=/data/home/tmp/podnotes-MOB1 MOB1_PROFILE=1 fnm exec --using 22 -- node --experimental-strip-types .obsidian-e2e-artifacts/MOB1/drive.mjs ``` The timing investigation finished within 20 minutes of the coordinator's 30-minute instruction, including the wait for the already-running older-version suite. The fixed bundle was restored and SHA-256 matched `fixed-main.js`. The isolated instance and fixture server were stopped. ## Checks Node v22.23.2. Commands ran with `fnm exec --using 22 --` and scratch under `/data/home/tmp/podnotes-MOB1`. - `npm run lint`: pass, zero errors or warnings. - `npm run format:check`: pass. - `npm run typecheck`: pass. - `npm run build`: pass. - `npm run test`: pass, Svelte checks clean, 126 files and 2,783 tests. - `npm run test:tooling`: pass, six files and 41 tests. - `npm run docs:build`: pass, 22 pages and all 112 legacy fragments resolve. - `npm run size`: 313,994 raw bytes and 101,443 gzip bytes at level 9. Baseline was 314,501 raw and 101,597 gzip. Delta is -507 raw and -154 gzip. Budget is 103,000 gzip. The full Obsidian 1.14.4 run passed all 242 tests across 32 files in 944.80 seconds, starting with a fresh vault. See `full-e2e.log`. The full Obsidian 1.13.7 run also passed all 242 tests across 32 files in 932.00 seconds on a fresh vault. See `floor-e2e.log`. Both suites reported no uncaught renderer errors and stopped their instances. Closed-view playback, command, API, and timestamp-link coverage includes J-PLAY-12, J-API-06, and J-URI-07. Mobile and desktop onboarding journeys check fresh-install-only opening. ## Dormant playback `dormant-playback.mjs` served **Fixture Episode 1**, a 60-second WAV, from `http://podnotes.test:21353/feed.xml`. After restoring a hidden phone sidebar, the leaf remained deferred and unmounted while API playback advanced the audio. Stop and start commands paused and resumed it. The URI `obsidian://podnotes?episodeName=Fixture%20Episode%201&url=http%3A%2F%2Fpodnotes.test%3A21353%2Ffeed.xml&time=20` sought to 20 seconds and revealed the view. No runtime errors occurred. Raw observations are in `dormant-playback.json` and `.log`. ## Review and scope History and implementation ran on `claudeAgent/claude-opus-5-5`. Focused independent reviewers `claudeAgent/claude-fable-5-1` and `codex_pool/gpt-6-astra` found no critical or warning issues. Both traced lifecycle ownership and checked that the picker test rejects command-only mounting. Only comments were deleted. A suggestion to add a journey ID was left out under standing order 36 because it does not affect coverage. The fix deletes the gate, view registry, and their now-unused methods. The mechanical removal of obsolete members in `src/types/IPodNotes.ts` accompanies their deletion from the implementation. Test stubs and gate-only expectations were removed. `EpisodesPage.svelte`, playback, public API and URI logic were not changed. No settings or storage migration is needed. ## Docs at release In `docs/src/content/docs/mobile.md`, under **Open the player**, add this sentence after the opening instructions: > If the player is already in your layout, swipe left from the right edge to open the sidebar, then select **Podcast Player** in its view picker. Published documentation is unchanged in this PR.