# Issue 14691 — passive refresh proof audit, pass 1

**Verdict: client proof incomplete. All ios-swift runtime rows below are UNVERIFIED / cannot-verify ios-swift.** This is a read-only source audit and a recording plan, not a reproduction of client behavior.

Compared base `4619c0bca6` to HEAD `6b0ce9b0bc70939c7cd1a81a009b0af70077fed5`. Only NativeFeatureClient.swift and NativeMultiEnvironmentTests.swift change. No PR state was queried in this refresh; no PR was created by this audit. No native scripts, builds, tests, browser, or servers were run for this audit. Scratch output is confined to `/tmp/issue-14691`. The supplied runbook exception permits cannot-verify ios-swift on Linux without Xcode/iOS SDK; the runbook itself was not located in the searched checkout/docs/skills, so that exception is attributed to the task brief rather than an independently read document.

## Existing evidence and its boundary

[Host runtime transcript](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/b6158405819336ba/host-runtime-transcript.txt): host main `8d3b061121`, three isolated real servers, protocol 2, real B RPC creation/rename. B returned renamed shell in 20 ms while C took 4534 ms, and 27 ms while C took 6520 ms. The local transcript was read. This establishes server independence and available B data; it establishes neither Swift polling nor UI publication, timing, cancellation, timeout handling, nor base/head visual difference. These captures cannot fill any row below. No credentials or actual user data are reproduced here.

## Minimal seed and capture harness requirements

Use independent disposable app storage and three isolated real host homes: A active, B healthy passive, C controlled passive. All enabled, protocol 2, authenticated with test-only credentials. Give each environment one project and two stopped threads, including identical raw project/thread IDs across B/C, distinct visible names, and one long title. Save one last-known C shell for failure cases. Keep providers stopped unless a row explicitly requires real working/approval state. Never run a fixture against live user state.

A future **native** capture driver must build/install the actual Swift target on an Xcode host and use the real app transport. It must record the app, not a mock transport, recreated SwiftUI screen, source-reading demo, or React Native substitute. Execute the same seed, mutations, delay plan, and viewport against base and head. Record build SHA, iOS/device/version, appearance, logical viewport size, app cache state, host SHA, scenario ID, and sanitized request timestamps. No native driver is claimed to have been supplied or run here.

Required driver operations (requirements, not invented existing CLI flags): seed/reset A/B/C; pair through supported production flow; real RPC rename/create/archive/delete and real stopped/running/approval/input states; delay/release a selected endpoint by environment and request ID; return transport failure or 401; record shell request start/end/cancel, auth-session and catalog RPC completion, and active/passive socket ownership; request environment enable/disable/remove/re-pair/switch through the app; background/foreground the app; begin/end continuous video with monotonic timestamp correlation. Network control must preserve real server responses for success rows. Scripted fault injection must be labelled as such. No secrets, pairing URLs, tokens, live content, or unredacted network dumps in uploads.

Each matrix row requires continuous real-app **video**, plus correlated sanitized request events; a screenshot alone cannot prove interaction or elapsed time. Start before the mutation/tick, show the relevant visible rows/connection status, keep through completion and at least the next relevant poll. Exact request start times come from logs, not eyeballing video. For absent-request assertions, retain logs for the whole observation window. Use endpoint-observed milestones to orchestrate releases; preserve wall-clock production cadence in the app. Record timing tolerance/device load rather than asserting a hard five-second UI SLA.

## Minimum affected-behavior matrix

Every row: ios-swift, real app, **UNVERIFIED**, recording required. Rows with slash-separated variants require individually labelled segments; one clip may contain several segments only when their timing boundaries remain distinguishable. Baseline A active is kept throughout unless specified. Delay C shell below six seconds for a successful late answer, above six for timeout; do not assume a 6500 ms shell delay succeeds with the client's six-second timeout. Delayed route fallback and later RPC stages can make total load duration longer.

| ID | Caller / seed and action | Timing / acceptance and required recording |
|---|---|---|
| R1 | Foreground merged home; warm catalog/cache; B rename while C shell is held 4.5 s; repeat with B/C labels and response order swapped | On head, changed healthy row appears before held peer completes; next healthy shell begins after its completion plus fast 5 s without waiting for C. Base/head video and timestamps; include a second healthy mutation on the next poll. Hold C across a later tick using an ancillary-stage delay for R3 if the 6 s shell limit prevents it. |
| R2 | Same home, B/C both unchanged and quiescent; then mutate B immediately after an idle poll | Initial timer is 5 s; unchanged success selects idle 10 s; change selects fast 5 s for next poll. Show at least two unchanged cycles then changed cycle. Do not claim mutations during idle arrive within 5 s: idle wait plus endpoint work applies. |
| R3 | B fast, C pending across multiple ticks (hold authSession/catalog or route fallback as well as shell); mutate B twice | Healthy rows/cadence continue; at most one aggregate load for C at a time; C request is not restarted at each B tick. Record pending request ownership, two B updates, C release and its eventual row. R1 alone does not cover an outstanding request spanning two ticks. |
| R4 | B unchanged succeeds first (arms 10 s); C then returns changed shell or unchanged-but-busy shell before that timer fires | Late C publishes immediately; the next tick uses the earlier of the existing pending deadline and late completion + 5 s. Shorten only when the latter is strictly earlier; preserve the pending deadline near expiry. Record early-shortening and near-expiry preservation, stale tick rejection/no duplicate scheduling, separately for changed and unchanged-busy answers. |
| R5 | One passive remains busy while the other answers first; then busy-to-idle transition. Variants: session starting/running, latestTurn running, pending approval, pending input, background working/monitoring | Seven predicate variants must be visibly/semantically seeded. Each keeps 5 s cadence even when shell payload is unchanged; clear the predicate and demonstrate return to 10 s when all quiescent. Include a busy C load spanning later B-only cycles to test whether cached C work remains represented in cadence. These variants share the scheduling branch but not their source data requirements. |
| R6 | C timeout/unreachable with saved rows, B changes or remains busy; then C recovers | B publishes without waiting for C failure; C retains last-known rows with disconnected indication. Transient failure records an absolute ContinuousClock deadline at failure handling + 20 s, not a decrementing tick budget. C is eligible only on a later tick at or after that deadline; an early/pulled-forward tick must not retry it. B stays fast; recovery clears the deadline and publishes. Record >20 s from failure, timestamps and all request counts, including a failure arriving mid-wait and multiple earlier ticks. Repeat all-passive-failure/recovery; eligibility is not an exact 20 s dispatch guarantee. |
| R7 | Passive C credential rejected; B healthy; then re-pair C | C does not retry each 5/10 s; absolute retry deadline at failure handling + 24 h, evaluated on subsequent ticks; re-pair replaces runtime/restarts refresh and permits recovery. A short clip plus request log proves only the observed suppression window, not 24 h. Exact full-duration suppression remains unverified without a real-duration capture or separately labelled scheduler test. Single-route/direct and managed/multi-route reachability distinctions require labelled segments. |
| R8 | B genuinely empty shell (no projects/threads), then project/thread creation, rename, archive/removal; C delayed; raw IDs collide across B/C | Successful empty shell counts as success, removes stale B rows only, and can arm idle cadence. Each subsequent real change appears without cross-environment overwrite. Pair same-ID seed with R1 rather than duplicate a whole platform matrix. Include at least one project-only shell change and thread removal, not title-only evidence. |
| R9 | Settings disable/re-enable C or remove C while its read is pending; release old answer; add/re-pair same environment as applicable | Removed/disabled rows and permissions must not revive from old answer; healthy B continues and re-enable/re-pair can refresh. Disable and removal have different invalidation paths; both need segments. Capture catalog update before/after tick and after old response release. |
| R10 | Switch active A→B while C pending; disconnect/sign out during a second pending read; separately replace active route/re-pair | Old session cannot publish a late snapshot, steal active selection, revive stale permission or schedule more ticks. New active has correct stream and passive set; cancellation terminates owned work. Release old reads after switch/disconnect, observe >10 s. R9 cannot substitute: generation/session ownership differs. |
| R11 | Home start/reload with warm read cache vs cold storage; return foreground after <10 s and ≥10 s background | Record startup snapshot, first aggregate publication, and resumed updates without stale replay. Cold initialSnapshot and cacheStartupRefreshTask still batch all enabled loads; label any wait there separately, not a failed proof of the narrower passive-loop fix. Resume does not itself start aggregate refresh, so demonstrate continuity/replacement through actual lifecycle. |
| R12 | No passive environments (only A, disabled B/C); then enable B | No passive shell requests; loop selects idle 10 s and discovers newly enabled B on a later tick. Record enable action through discovery and next publication. Include all-passives-in-backoff observation with R6/R7 to distinguish it from empty passive set. |
| R13 | Environment document load transient failure while existing load completions are pending, then recovery | Persistence failure uses 20 s retry; queued completions must not strand refresh or republish removed rows. This requires an isolated storage-fault seam on the native host; real UI recording plus fault log. If no reliable seam exists, explicitly retain UNVERIFIED, do not fabricate a UI repro. A slow persistence read can also block the event consumer; the diff does not remove that await. |
| R14 | C primary route unavailable with working alternate route; B healthy; repeat over remote/relay/tunnel if available | B independent while C resolves; C recovers on selected route without disconnecting newly active shared client. Capture real route labels/status and requests, not a mock server catalog. Local-host-only evidence cannot establish managed relay/tunnel behavior; unavailable credentials/routes remain unverified. |
| R15 | Selected passive B thread detail while home aggregate updates; return to merged home; compare background snapshot path | Detail selection must keep owning-environment routing/live stream; aggregate publications update shared rows without wrong connection/detail identity. Bounded backgroundSnapshot still batch-awaits and must not create long-lived subscriptions/timers. Record interaction/lifecycle and traffic; separate path from recurring refresh. |

## Platform, theme, width and entry-point reduction

No rendering/layout/appearance code changes. Collapse theme × width Cartesian products only: run the main timing pack R1–R8 on iPhone compact/light, replay R1 with long colliding titles on iPad regular/dark, and rotate compact↔regular during a pending response in R10 or R11. Record actual point widths and row/status legibility. This is a scheduling audit, not a claim that untested visual combinations passed. Both native iPhone/iPad targets are relevant because the same Swift client drives them. Minimum supported iOS 17 and a current installed iOS runtime should be identified; if only one is available, report the OS coverage gap rather than implying all versions.

Merged home rows/reachability are the direct consumer; Settings enable/remove/pair, reload/start, app lifecycle, active-route replacement and passive detail selection affect loop ownership. No changed command-palette/keybinding implementation exists in this diff; do not add unrelated per-control rows. Provider adapters are unchanged: cadence reads provider-neutral shell state, so collapse provider-brand permutations, **not** the seven active-work predicate shapes. Web/Electron/React Native are outside this Swift change; their captures cannot prove it. Widgets/background refresh use a distinct snapshot path and need a boundary/lifecycle check, not a duplicate foreground cadence matrix. Local/remote/relay/tunnel share scheduling but differ at route/error boundaries; R14 retains those variants.

## Source contract and cadence observations

Source inspected at final HEAD: `apps/swift-ios/App/NativeFeatureClient.swift` recurring loop and `apps/swift-ios/Tests/FeatureTests/NativeMultiEnvironmentTests.swift` passive-refresh tests. Source observations are not runtime evidence.

The diff removes the aggregate barrier *inside the recurring passive loop*: one child task per eligible passive environment, completion events independently reconcile/publish, in-flight environments skipped, first successful answer schedules the next tick, late changed/busy answers can pull the pending deadline earlier but never postpone it, tick IDs reject canceled/stale timers, loop teardown cancels outstanding tasks. It retains session/refresh-ID guards and generation-aware reconcile. Passive shell reads remain one-shot HTTP; uncached catalog uses a bounded ephemeral RPC, not a persistent passive subscription. Shell fetch defaults to 6 s but load completion also waits for authSession and possibly serverConfig/route recovery.

Cadence is **completion-relative**, not fixed-rate: first tick 5 s after loop start; changed or busy result requests 5 s; unchanged idle success requests 10 s; environment-document failure requests 20 s; transient per-environment failure records 20 s and credential rejection 24 h. Final HEAD replaces decremented tick budgets with absolute ContinuousClock retry deadlines measured from failure handling: transient +20 s, credential rejection +24 h. Eligibility is checked at subsequent ticks, so actual retry may occur later; earlier ticks cannot consume the backoff. All in-flight/all-backed-off selects a 5 s retry tick. First failure alone does not schedule until another success or the current cycle empties. Thus neither absolute five-second visibility nor exact wall-clock 20 s/24 h retry is proved by constants. Initial/background/cache-startup loads still batch; no fix to those barriers is present.

**Review hypotheses requiring proof, not established defects:**

1. `cycleEnvironmentIDs` and `cycleNeedsFastRefresh` are overwritten at each dispatch batch. A cached busy C skipped because still in flight is not included in B's later unchanged result; B may select idle despite known C work. R5 must keep C pending across B-only cycles, not merely release it once.
2. Old C completion can arrive during a newer B cycle and affect its timer. R3/R4 must distinguish old/new batch ownership; the independence test checks a held-read count but disconnects after release; the separate final-head deadline test targets only near-expiry changed-answer preservation. Neither proves all overlapping-cycle ownership variants.
3. `environments` is a tick-cached catalog, reused for each loaded event. Saved/disabled changes between ticks and old completion need R9/R10; reconcile rejects revoked/generation-invalid loads, but enable/disable and removal have different paths. In particular, disabled entries remain saved IDs, and setEnvironmentEnabled itself does not increment loadGeneration. Do not declare stale-row/permission safety from the presence of a general generation check.
4. Environment-list loading is awaited on the single event consumer. Slow persistence can delay even already queued healthy completion publication; per-environment task isolation is not blanket isolation of all stages.

## What the source tests do and do not establish

Inspected, never executed: independent healthy publication/no duplicate held load; late changed-answer deadline preservation with injected manual clock; failure answered mid-wait with absolute retry accounting; existing failed-peer behavior updated to advance the manual clock and await the second failed-shell-read milestone. The mid-wait case models failure at 11 s, not due until 31 s, no retry at 25/30 s, then retry at 35 s. These are mock/manual-clock test intentions, not compile results, passing tests or production timing proof.

Early shortening, busy-only late answers, stale/canceled tick delivery, sustained cached busy work, native lifecycle/ownership and all R1–R15 recording variants remain unverified. No Swift build/typecheck or test execution evidence was produced.

## FRICTION

- **Cannot verify ios-swift:** Linux runner has no Xcode/iOS SDK; the task prohibits native fixture execution, browser and servers. Every Swift row stays UNVERIFIED. No real-app capture exists in this pass.
- **Runbook provenance:** cannot-verify allowance is explicit in the brief; a matching runbook was not found in the searched locations. No quotation or independent runbook compliance claim is made.
- **Host/client mismatch:** supplied host evidence is main `8d3b061121`, whereas target is Swift HEAD `6b0ce9b0bc`; server timing proves data availability only. Preserve that boundary in any parent report.
- **Fixture/capture gap:** this artifact specifies required driver capabilities and seeds; it does not claim a working native scenario driver or recording bundle. Real native capture host, fault seams, test routes, and sanitized request/video correlation remain prerequisites.
- **Public output:** the three sanitized matrix/index/audit artifacts are authorized for upload. No issue/PR/comment/repository write was performed; no PR was created.

## Final-head refresh — 2026-10-22

Target HEAD `6b0ce9b0bc70939c7cd1a81a009b0af70077fed5`, base `4619c0bca6`. Read-only source inspection only; no build, tests, native capture, browser, server or device access attempted. All 15 rows remain UNVERIFIED / cannot-verify ios-swift; captures 0; verified 0/15. The task-brief exception permits a Swift PR with that disclosure but does not establish passing proof.

**VERDICT: INSUFFICIENT.** Exact missing rows: R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15, with every variant above still required.
