The switches that bisect a render bug can be reached from the phone #146

Merged
viberfox-agent merged 1 commit from feat/debug-switches-on-the-device into main 2026-08-23 21:38:38 +00:00
Collaborator

On the Adreno 840 black sky, CARTO_GROUND_RAYMARCH was built on 2026-08-19 to answer one question and was still unanswered four days later, because reaching it needed adb — a cable and a second machine.

The CARTO_* switches are now a persisted preference too (Settings ▸ Graphics ▸ Developer, collapsed, header counts what is on). env_flag resolves the two: an explicit env var or debug.carto.* property is an instruction for this launch and wins in both directions; the preference is the fallback. Resolving it inside env_flag means every switch in the codebase became reachable from the phone without one call site being edited.

The diagnostics report gains a debug switches: line by env name, so a switched run cannot be mistaken for a clean one.

Verified: 652 client tests, cargo fmt --check, cargo check -p cartopolis_android --target aarch64-linux-android, headless captures on lavapipe under CARTO_QUALITY=android.

On the Adreno 840 black sky, `CARTO_GROUND_RAYMARCH` was built on 2026-08-19 to answer one question and was still unanswered four days later, because reaching it needed `adb` — a cable and a second machine. The `CARTO_*` switches are now a persisted preference too (Settings ▸ Graphics ▸ Developer, collapsed, header counts what is on). `env_flag` resolves the two: an explicit env var or `debug.carto.*` property is an instruction for this launch and wins in both directions; the preference is the fallback. Resolving it inside `env_flag` means every switch in the codebase became reachable from the phone without one call site being edited. The diagnostics report gains a `debug switches:` line by env name, so a switched run cannot be mistaken for a clean one. Verified: 652 client tests, `cargo fmt --check`, `cargo check -p cartopolis_android --target aarch64-linux-android`, headless captures on lavapipe under `CARTO_QUALITY=android`.
feat(dev): put the bisecting switches where the phone can reach them
All checks were successful
CI / test cartopolis (pull_request) Successful in 8m7s
CI / wasm & android targets (pull_request) Has been skipped
7b13f77774
`env_flag`'s doc has said for months that Android has no environment, so the
`CARTO_*` switches arrive as `debug.carto.*` system properties set with `adb
shell setprop`. Accurate, and not enough: adb is a cable and a second machine,
and the phone is usually not where the workstation is.

The bill came due on the Adreno 840 black sky. `CARTO_GROUND_RAYMARCH` was built
on 2026-08-19 to answer one question — is the sky-view LUT the fault, or the
whole pass? — and four days later that question was still open, because nobody
holding the device could switch it on. The instrument existed, was correct, and
was unreachable. Worse, the hypothesis it was built to test shipped a workaround
(c91ac25) which the device has now falsified, so the four days bought nothing.

So the switches are a persisted preference too, and `env_flag` resolves the
two: an explicit env var or property is an instruction for *this launch* and
wins in both directions; the preference is what a launch falls back to and is
never written back. The same rule `--connect` follows against the remembered
session.

Resolving it inside `env_flag` rather than at the call sites is the point —
every switch in the codebase became reachable from the phone without one of them
being edited.

Four things are load-bearing:

- **Absence and `=0` must be different answers.** `env_flag_explicit` returns
  `Option<bool>`. Collapsed to a bool, `setprop debug.carto.x 0` to overrule a
  preference that is on would fall through to that preference and appear to do
  nothing — the worst behaviour available for a debugging switch. The rule is a
  free function (`resolve_flag`) with its own tests, for the reason
  `frame_pacing::resolve_frame_rate` records: a `OnceLock` and a process
  environment are untestable, and the rung test there stayed green about a number
  the call site had stopped passing on.

- **The seed is earlier than it looks.** `CARTO_NO_DUAL_SOURCE` is consulted
  while `DefaultPlugins` is assembled, several hundred lines before
  `UserStore::load()`. `init_debug_switches` sits beside `quality::init` at the
  top of `run_client`, fed by the same narrow `serde_json::Value` read
  `preferred_quality` uses — deserialising `UserData` that early runs
  `LayerPrefs`' defaults, which settle the tier's `OnceLock` from a detection
  that has not been told the user's preference yet.

- **Named fields, not a map.** `AppPrefs` is `Copy`, and a free-text key is a typo
  that silently does nothing — the argument the shot manifest already makes for
  rejecting an unknown key. `DebugSwitches::SWITCHES` is the one table the UI, the
  lookup and the tests read, and two tests pin the table and the struct together
  in both directions.

- **A report from a switched run has to say so.** They are reachable from a
  settings screen now, so somebody can set one and forget. The diagnostics report
  carries `debug switches:` by env name — resolved rather than as stored, so it
  can be pasted back as a `setprop`.

The section is collapsed, last in Settings ▸ Graphics, and its header carries a
count when any are on: several of these make the picture worse on purpose, and a
run with one set is a run whose rendering proves nothing.

Verified: 647 client tests, `cargo fmt --check`, `cargo check -p
cartopolis_android --target aarch64-linux-android`, and headless captures on
lavapipe under `CARTO_QUALITY=android` with the atmosphere radius either way
(both draw a correct sky here — the Adreno fault does not reproduce on lavapipe,
which is the whole reason this had to reach the device).
Sign in to join this conversation.
No description provided.