Skip to content

Device lanes: iOS app and APK in the machine-wide native cache, keyed by every build argument and the module assignment; -Onone case code checked to be construction only - #175

Merged
thejackshelton merged 5 commits into
masterfrom
app-build-cache
Oct 5, 2026
Merged

thejackshelton merged 5 commits into
masterfrom
app-build-cache

Conversation

@thejackshelton

@thejackshelton thejackshelton commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

What changed (DEVICE-SPEED, COMPILE-SPEED design decision 3; includes #166's stamp Low): the iOS host app and the Android APK now build into #158's machine-wide native cache (~/.cache/dragon-native, or DRAGON_NATIVE_CACHE, which CI can point at an actions/cache path). Before, each was reused only inside one worktree.

The cache

The key (#166 review Low): a sha256 over:

  • the source tree and Ahem (reuseStamp);
  • every build command exactly as it runs, written with $W for the build directory and $TOKENs for host paths. The commands are iosCommands (each swiftc call with its flags and file list, so the module assignment and each module's -O or -Onone are hashed, plus cp and codesign) and androidCommands (aapt2, kotlinc, d8, zip, zipalign, apksigner);
  • the inputs the tokens stand for:
    • iOS: the simulator SDK version and swiftc -version. The Xcode version is already in the sources.
    • Android: the build-tools version, the content of android.jar, kotlin-stdlib.jar and the keystore, and java -version. kotlinc's version is in the sources.
  • the host OS and architecture.

The IOS_BUILD label is gone. -j is the $CORES token, because the parallel width changes no output. An unknown token throws, so no literal $NAME ever reaches a tool.

The -Onone content check (optional item): before an iOS build, every DragonCases source (the code built at -Onone) must be construction code only:

  • no if, guard, else, loops, switch, break, continue, throw, try or defer;
  • no ternary, except the typed state setters' Bool encoding v ? 1 : 0;
  • no assert, precondition or fatalError;

all judged outside string literals and comments. An enum's case is a declaration, so it is allowed. On today's sources: 0 problems, checked in 85 ms.

Measured (load 11–43):

  • iOS app: cold 58 s, a hit 6 s (the 6 s is computing the case list).
  • APK: cold 102 s, a hit 6 s.
  • In a device run with the app ready, both prebuilds took 18 s together.

Every worktree's first device run, and every land checkout, now skips the app builds unless the app sources changed.

Proof. A full local device run (appcache, through /tmp/device-lease.sh, both apps from the cache) was compared with master's committed records:

  • the land driver's deviceRunProblems: no problems;
  • both device-failures-*.json: byte-identical (57 iOS, 86 Android);
  • lanes.json: 0 differences outside evidence.laneCode.

Also:

  • native:build -- --target ios --plant ios-16: still caught by availability checking. The failed build's work directory was removed.
  • native:build -- --target android: the API floor check passes over the cached dex.
  • --plant api-34: still caught.

Tests:

  • device-lanes.test.ts adds:
    • the key changes with an optimisation flag, a file moved between modules, the source tree, an input, the keystore and a kotlinc flag;
    • tokens expand, an unknown token throws, and the token sets are exactly the ones supplied;
    • the content check: today's sources pass, and each construct is caught; string literals, comments, enum cases and the Bool encoding pass.
  • suite-errors.test.ts adds: ios-app and apk entries are pruned with the harness builds under the one cap.
  • vitest run suite-errors, device-lanes, lanes-concurrent and state-cases: 119/119 pass.
  • pnpm typecheck: pass.

Device step pending: lanes-records, p6a-promotion and device-failures fail only because native-host.ts is in EVIDENCE_CODE.

Outside the spec:

Review round (precomputed review of f15d5ee), head below:

  • The setter exemption: the state emitter writes v ? ${t} : ${f}, with numbers that follow the fixture's value order. The exemption is now that whole shape, v ? <int> : <int>, so a fixture whose first case sets a boolean true (v ? 0 : 1) builds.
    • The test checks the emitter's exact template in state.ts, and several value orders.
    • Any other ternary is still caught: a non-integer branch, another variable, or a fractional number.
  • Forced rebuilds: with reuse off (native:build), the fresh build now replaces its entry (replace in build-cache.ts). The old entry is renamed aside, the build renamed in, and the old one deleted, so a forced rebuild repairs a damaged entry. A build another process published in between is kept.
    • Tests cover a damaged entry and a missing one.
    • Real run: native:build -- --target ios replaced the entry, and the next prebuild hit it.
  • Tests: 120/120 pass (suite-errors, device-lanes, lanes-concurrent, state-cases). pnpm typecheck: pass.
  • No new device run: the app key is unchanged (same entry 7dd6de18…), and only the check and the publish path changed.

🤖 Generated with Claude Code

…ive cache, keyed by every command argument, the module assignment and the tool inputs; the -Onone case code is checked to be construction only
…ue order (v ? <int> : <int>); a forced rebuild replaces its cache entry
Commands: pnpm regen; pnpm run parity:devices; pnpm regen
@thejackshelton
thejackshelton merged commit 3114104 into master Oct 5, 2026
5 checks passed
@thejackshelton
thejackshelton deleted the app-build-cache branch October 5, 2026 15:57
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.

1 participant