Skip to content

feat(config,android): configure emulator launch options from the config file (#148) - #149

Merged
V3RON merged 4 commits into
mainfrom
task/148
Oct 1, 2026
Merged

V3RON merged 4 commits into
mainfrom
task/148

Conversation

@V3RON

@V3RON V3RON commented Sep 27, 2026

Copy link
Copy Markdown
Contributor

Closes #148

Operators can now set how this machine's Android emulators launch, in ~/.simlock/config.json under android.emulator (headless, gpu, audio, bootAnimation). It is config-only, like ios.slim: the daemon hands the block to the Android driver, and no lease request, MCP call, or HTTP request can set it.

The driver maps each key to one fixed flag after -no-snapshot-save (-no-window, -gpu <mode>, -no-audio, -no-boot-anim). There is no pass-through: an unknown key under android.emulator is warned about and dropped. headless and gpu enter the clean-baseline hash, so the snapshot rebuilds on the next boot after either changes. They are added to the hash only when they differ from the defaults, so baselines captured before this change keep their hash and are not wiped on upgrade.

Review found that the Android driver ignored makeReady's purpose: "recover", so a hash mismatch would have wiped a still-leased device during crash recovery after a restart. A recovery boot is now a cold boot with no baseline check, no snapshot load, no wipe, and no capture; the baseline decision waits for the next reclaim.

docs/CONFIGURATION.md documents the keys, their validation, the next-boot and snapshot-rebuild rules, and the gateway-ignored lists.

Done when

  • Every spec test passes: src/drivers/android/index.test.ts ("android.emulator launch options"), src/core/config.test.ts, src/daemon/dispatcher.test.ts (BAD_REQUEST), src/daemon/main.test.ts (threading), e2e/daemon-lifecycle.test.ts (simlock config). Each was broken on purpose and seen to fail; the reviewers' mutations are caught too.
  • pnpm check green on the head commit.
  • simlock config shows the block (e2e); CONFIGURATION.md documents the four keys, the next-boot rule, and the snapshot-rebuild rule.
  • Default launch is byte-for-byte unchanged: asserted as exact argv with the option omitted and with explicit defaults, and the pre-change baseline hash is pinned against the driver on main.

Review

Spec review: 6 findings, 1 fixed; round 2: 8 findings, 0 fixed. Code review: 6 findings, 3 fixed; round 2: 4 findings, 3 fixed.

Rejected:

  • The recovery-boot branch is behaviour the spec did not ask for, and no core caller passes purpose — safety rule 2 and the Driver.makeReady contract require it, and ManagedDeviceLifecycle.recoverLeased on main already passes { purpose: "recover" }. Spec needs: "a recovery boot never wipes, loads a snapshot, or captures a baseline".
  • The recover test's title states a claim the spec never made — it states the claim the rules make; same reason.
  • The gateway-ignored key handling was not extended — the existing allowlist already ignores any top-level key it does not read; the test proves it and the docs lists were updated.
  • The gateway test does not check the value is ignored — in this codebase "ignored" means nothing in gateway mode reads it; the value is still parsed and merged so one file serves both modes, as the existing lease.* gateway test states.
  • headless/gpu enter the hash only when non-default, not always — deliberate, so a baseline captured before this change keeps its hash and an upgrade does not wipe every device; now pinned by a test against the pre-change hash.
  • Folding #configHash into #currentConfigHash, and extracting #reconcileBaseline/prepareLaunchArgs — the first puts the hash inputs in one place, the second keeps makeReady under the repo's complexity gate.
  • The unknown-key test is one the spec did not list — it proves the "no free-form launch argument" line of Scope; its title was narrowed to what it proves.
  • The e2e test's fast-lane membership cannot be confirmed from the diff — untagged e2e tests are the fast lane; only slow-tagged ones are excluded.
  • The discovery test does not exercise audio/bootAnimation — it proves threading with two non-default values; flag mapping is the driver's own tests.
  • The core now declares a platform-specific config block — the spec asks for it beside ios.slim, the precedent ADR 0002 set.
  • The golden hash 4e9b7a98 is unproven as pre-change — it was verified by running the test against the driver checked out from main.

Written by an agent.

🤖 Generated with Claude Code

https://claude.ai/code/session_01PvsMWpwkPBL4Zo2ppLTxDA


Generated by Claude Code

…ig file (#148)

Adds an operator-only `android.emulator` block (headless, gpu, audio,
bootAnimation) that the daemon hands to the Android driver unread. The
driver maps each key to one fixed emulator flag after -no-snapshot-save;
headless and gpu enter the clean-baseline hash so the snapshot rebuilds
when either changes. Defaults launch exactly as before.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PvsMWpwkPBL4Zo2ppLTxDA
…th, tighten gpu docs (#148)

`makeReady` now honours `purpose: "recover"`: a recovery boot is a cold boot
from disk with no baseline-hash check, no snapshot load, no wipe, and no
baseline capture, so a changed `android.emulator.headless`/`gpu` (or any other
hash input) can never erase a device that is still leased. The baseline
decision moves into `#reconcileBaseline` and `prepareLaunchArgs`.

Tests now pin what the launch-option hash inputs promise: a baseline captured
before `android.emulator` existed keeps its hash under the default launch, a
change between two explicit gpu modes rebuilds the baseline, an audio change
under non-default headless keeps it, and recovery boots cold. Narrowed one test
title to what its body proves. Docs say the emulator, not Simlock, validates a
gpu mode.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PvsMWpwkPBL4Zo2ppLTxDA
…u schema (#148)

The recover-purpose test now asserts the mark write, so dropping it goes red.
The contract schema's `gpu` requires a non-empty string, matching the loader.
The core config comment no longer claims the block is handed over unread.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PvsMWpwkPBL4Zo2ppLTxDA
…one-shot check (#148)

Rotation renames daemon.log away and then opens a new one, and with a
200-byte cap nearly every startup line rotates, so a check from another
process can land between the two. CI hit that gap once the startup config
line grew by the android.emulator block.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PvsMWpwkPBL4Zo2ppLTxDA
@V3RON
V3RON merged commit 214b4f2 into main Oct 1, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Configure Android emulator launch options (headless, GPU, audio, boot animation) from the config file

2 participants