fix(qemu): force TCG for arm64 CHR on all Apple Silicon, add --accel override - #99
Conversation
…override
The unreleased FEAT_SSBS=0 fallback keyed on the wrong axis. SSBS was a
coincident marker of the M4 host that first reported the panic, not the
mechanism: Linux 5.6 treats SSBS as an optional mitigation and boots fine
without it (cortex-a53/neoverse-n1 lack it too).
Real cause is the CHR image. arm64 CHR (7.20.8-7.23beta5 verified) pairs an
AArch64 kernel with a 32-bit ARM userspace: the appended initramfs /init is
ELF 32-bit LSB ARM EABI5, and the 7.22.1 system package holds 101 more ARM32
executables and 18 ARM32 shared objects. Apple Silicon implements no AArch32
at any exception level, and HVF passes the hardware ID_AA64PFR0_EL1 straight
through -- the -cpu model is inert -- so the guest never sets
ARM64_HAS_32BIT_EL0, execve("/init") returns -ENOEXEC, and Linux panics at
t~0.076s with "No working init found".
Consequences: the fallback must cover every Apple Silicon generation, not
M4+ (the old predicate left M1/M2/M3 on HVF and panicking), and a QEMU
version floor is not a valid restore signal -- Hypervisor.framework exposes
no feature-register setter, so the deferred getQemuVersion() guard is
dropped rather than postponed. The restore signal is a future arm64 CHR
image whose required userspace is AArch64 throughout.
- detectAccel("arm64") returns tcg on all macOS hosts; hostLacksSsbs()/
ssbsTcgWarning() replaced by isAppleSiliconHost()/accelNote()
- new --accel <auto|tcg|hvf|kvm> on start/add, plus an `accel` setting and
QUICKCHR_ACCEL env var (flag > env > quickchr.env > auto). Non-auto is
passed to QEMU verbatim and bypasses detection, so HVF can be tested
against a future AArch64-only image without a code change
- doctor marks the acceleration row when an override is in effect
- settings.ts's file tier extracted to leaf module settings-file.ts:
importing settings.ts from platform.ts created a cycle (settings -> cache
-> state -> network -> platform) that loaded eagerly on every CLI start
and pushed cli-settings.test.ts past its 5s timeout. settings.ts
re-exports it, so the public API is unchanged.
Not reproduced locally -- dev/CI hosts are Intel x86_64 and this needs Apple
Silicon. M4 evidence is the reporter's (tikoci/mikropkl#11); the exact
"Failed to execute /init (error -8)" line remains unobserved. Verified here:
accelerator selection, the override, and a real x86 CHR boot under both auto
(-accel hvf) and forced (-accel tcg,tb-size=256).
Refs #97
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Both are domain vocabulary introduced by the arm64/HVF analysis (ID_AA64PFR0_EL1, Hypervisor.framework as a VMM). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughThe PR adds accelerator overrides through CLI, settings, and environment variables; forces TCG for macOS Apple Silicon guests; replaces SSBS-based detection; updates launch diagnostics, tests, documentation, and integration guidance. ChangesAccelerator policy
Estimated code review effort: 4 (Complex) | ~45 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
This PR updates quickchr’s QEMU acceleration selection to avoid HVF for arm64 CHR on Apple Silicon (forcing TCG by default), and introduces a process-wide accelerator override (--accel, QUICKCHR_ACCEL, and quickchr.env setting) so users can explicitly bypass detection when needed (e.g., to test future images).
Changes:
- Force
detectAccel("arm64")to returntcgon macOS, and replace SSBS-based messaging with an Apple-Silicon/AArch32 explanation viaaccelNote(). - Add an accelerator override chain (flag > env > settings file > auto) with validation (
AccelMode/parseAccelMode) and CLI wiring (--accel). - Break out
quickchr.envfile-tier logic into a leaf module (src/lib/settings-file.ts) to avoid import cycles and startup cost.
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
src/lib/platform.ts |
Adds accel override resolution + new accelNote(), forces arm64-on-macOS to TCG, updates host logic helpers. |
src/cli/index.ts |
Adds --accel flag handling (applyAccelFlag) and help text updates. |
src/lib/types.ts |
Introduces AccelMode, ACCEL_MODES, and parseAccelMode() validator. |
src/lib/settings.ts |
Adds the accel managed setting and re-exports file-tier helpers from the new leaf module. |
src/lib/settings-file.ts |
New leaf module for quickchr.env path/read/parse to avoid platform/settings import cycles. |
src/lib/quickchr.ts |
Switches to accelNote() and annotates doctor output when accel is forced. |
test/unit/platform.test.ts |
Updates acceleration tests for the new Apple Silicon behavior + override semantics. |
test/unit/settings.test.ts |
Updates expectations for the new 6th settings key (accel). |
test/unit/cli-settings.test.ts |
Updates CLI settings print/JSON expectations to include accel. |
MANUAL.md |
Documents the new accel setting and its precedence/behavior. |
DESIGN.md |
Updates decision #10 to the AArch32 userspace root cause and documents the override. |
CHANGELOG.md |
Adds --accel/setting/env and replaces the unreleased SSBS-based entry with the widened fix. |
docs/m4-hvf-arm64-investigation.md |
Updates implications section to reflect implemented fix/override and corrected root cause. |
.github/instructions/qemu.instructions.md |
Updates acceleration rules to reflect Apple Silicon arm64 TCG + override chain. |
.github/copilot-instructions.md |
Updates project QEMU rules summary to include the Apple Silicon arm64 TCG rule + override. |
project-words.txt |
Adds new vocabulary (pfr, vmm) for cSpell. |
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/copilot-instructions.md:
- Line 46: Update the arm64 macOS acceleration guidance in the documentation to
state that automatic selection uses TCG with “-cpu cortex-a710,” rather than
claiming it always does. Preserve the documented behavior that explicit --accel
or QUICKCHR_ACCEL values, including hvf or kvm, override the automatic policy.
In `@MANUAL.md`:
- Around line 401-412: Update the managed-key count reference near the
settings/environment-variable documentation from five to six, keeping the
surrounding explanation unchanged.
In `@src/lib/platform.ts`:
- Around line 200-205: Update accelNote in src/lib/platform.ts (lines 200-205)
and the doctor suffix in src/lib/quickchr.ts (lines 2008-2015) to use consistent
source-neutral wording such as “configured override,” or propagate resolver
provenance so messages accurately cover flag, environment, and quickchr.env
overrides under the existing flag > environment > quickchr.env precedence.
In `@src/lib/settings-file.ts`:
- Around line 13-31: Replace Node filesystem and path usage in
src/lib/settings-file.ts lines 13-31 and src/lib/settings.ts lines 16-17 with
Bun filesystem APIs and Bun path helpers, preserving existing settings behavior.
Update the atomic write flow in src/lib/settings.ts lines 182-212 to use Bun
equivalents for directory creation, writing, copying, syncing, closing, and
removal, and wrap any write, copy, fsync, or rename failure in QuickCHRError.
In `@src/lib/settings.ts`:
- Around line 105-109: Update the managed-key list used by the quickchr settings
help in the CLI entrypoint to include accel, documenting its supported AccelMode
values and the builtin default "auto". Use the existing settings metadata or
formatting conventions in the managed-key list rather than changing the settings
definition in parseAccelMode or the accel configuration.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: faf93995-d5e3-4e87-9993-aa2fd9967cc5
📒 Files selected for processing (16)
.github/copilot-instructions.md.github/instructions/qemu.instructions.mdCHANGELOG.mdDESIGN.mdMANUAL.mddocs/m4-hvf-arm64-investigation.mdproject-words.txtsrc/cli/index.tssrc/lib/platform.tssrc/lib/quickchr.tssrc/lib/settings-file.tssrc/lib/settings.tssrc/lib/types.tstest/unit/cli-settings.test.tstest/unit/platform.test.tstest/unit/settings.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (3)
- GitHub Check: copilot-pull-request-reviewer
- GitHub Check: Unit Tests (windows-latest)
- GitHub Check: Analyze (javascript-typescript)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
In Bun-based TypeScript code, use
Bun.spawn(),Bun.write(),Bun.sleep(),bun:test, and ESM imports with.tsextensions.
**/*.{ts,tsx}: Use Bun APIs andbun:test; do not use Node.js APIs or CommonJS. Use ESM with.tsextensions in imports.
For ARM64virtmachines, never useif=virtiofor drives; use explicit-device virtio-blk-pci,drive=drive0.
When using HVF acceleration, use-cpu host, notcortex-a710.
Arm64 guests on macOS must use TCG with-cpu cortex-a710;--accelandQUICKCHR_ACCELoverride this for testing.
UEFI pflash code and vars units must be identical in size.
QGA is x86-only; do not expect the guest agent to start for arm64 CHR.
Use Biome 2.x for linting, with tabs for indentation, and avoid unnecessary comments on obvious code.
ThrowQuickCHRError(code, message, installHint?)for errors.
Files:
test/unit/settings.test.tssrc/lib/types.tssrc/lib/settings-file.tstest/unit/cli-settings.test.tssrc/lib/quickchr.tssrc/lib/settings.tssrc/lib/platform.tstest/unit/platform.test.tssrc/cli/index.ts
test/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Do not turn a red integration test green by broadening timeouts, skipping it, or platform-gating it before reproducing and root-causing the failure.
Files:
test/unit/settings.test.tstest/unit/cli-settings.test.tstest/unit/platform.test.ts
test/unit/**/*.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Unit tests must be fast and must not require QEMU.
Files:
test/unit/settings.test.tstest/unit/cli-settings.test.tstest/unit/platform.test.ts
src/**
📄 CodeRabbit inference engine (CLAUDE.md)
Follow the rules in
general.instructions.mdfor files undersrc/**, including layer boundaries, error-code usage, port layout, and the RouterOS “expired admin” caveat.
Files:
src/lib/types.tssrc/lib/settings-file.tssrc/lib/quickchr.tssrc/lib/settings.tssrc/lib/platform.tssrc/cli/index.ts
src/lib/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Keep
src/lib/as pure library code: do not import fromsrc/cli/and do not callprocess.exit()there.Keep
src/lib/as pure library modules: no CLI dependencies and noprocess.exit().
Files:
src/lib/types.tssrc/lib/settings-file.tssrc/lib/quickchr.tssrc/lib/settings.tssrc/lib/platform.ts
src/cli/**/*.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Keep
src/cli/as a thin CLI wrapper over the library.
Files:
src/cli/index.ts
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: tikoci/quickchr
Timestamp: 2026-07-27T01:43:38.312Z
Learning: Keep `SKILL.md` and `references/quickchr-api.md` aligned with the repository, and update the relevant shared skill when QEMU/CHR behavior changes.
🔇 Additional comments (12)
.github/copilot-instructions.md (1)
46-46: 📐 Maintainability & Code QualityUpdate the paired shared skill documentation.
This QEMU/CHR policy change also needs the corresponding
routeros-qemu-chr/routeros-quickchrskill updates, or a linked follow-up if those live in a separate repository. Based on learnings, keepSKILL.mdandreferences/quickchr-api.mdaligned when QEMU/CHR behavior changes.Sources: Coding guidelines, Learnings
CHANGELOG.md (1)
11-20: LGTM!Also applies to: 22-42
docs/m4-hvf-arm64-investigation.md (1)
576-615: LGTM!project-words.txt (1)
275-275: LGTM!Also applies to: 430-430
.github/instructions/qemu.instructions.md (1)
37-39: 🎯 Functional CorrectnessNo documentation change needed.
.github/instructions/qemu.instructions.mddocuments Apple Silicon x86 CHR as TCG, whileDESIGN.mddocuments Apple Silicon x86 CHR as HVF, matching the currentsrc/lib/platform.ts:251behavior that selectshvffor any x86 guest on macOS.> Likely an incorrect or invalid review comment.src/lib/types.ts (1)
16-36: LGTM!src/lib/settings.ts (1)
23-25: LGTM!Also applies to: 161-180
test/unit/settings.test.ts (1)
296-299: LGTM!test/unit/cli-settings.test.ts (1)
51-69: LGTM!src/lib/platform.ts (1)
219-268: LGTM!test/unit/platform.test.ts (1)
1-1: LGTM!Also applies to: 12-16, 64-73, 388-504
src/cli/index.ts (1)
160-173: LGTM!Also applies to: 553-553, 1194-1195, 2741-2743, 2826-2828
mobileskyfi
left a comment
There was a problem hiding this comment.
Independent review at e7091bf:
The AArch32 root-cause chain in docs/m4-hvf-arm64-investigation.md supports the core policy: current arm64 CHR must auto-select TCG on Apple Silicon, while an explicit accelerator value must bypass detection for future-image testing.
I pushed the corrections that were clear from the current code and docs:
- Detect the physical Apple Silicon host under Rosetta via the documented
sysctl.proc_translatedprobe. This fixes the warning path and a larger latent bug: x86 CHR was still auto-selecting impossible x86/HVF on Apple Silicon. Both guest architectures now auto-select TCG there; Intel x86 keeps HVF. - Correct cross-architecture timeout classification for x86-on-arm64.
- Make repeated
--accelvalues use the last value and reject a missing value instead of silently ignoring it. - Use source-neutral configured-override wording for flag, environment, and
quickchr.envtiers. - Align
MANUAL.md,DESIGN.md, the QEMU instructions, settings help, managed-key counts, changelog, and integration-test comments. The manual previously still told native Apple Silicon users they would get arm64/HVF. - Add focused unit coverage for native Apple Silicon, Rosetta, Intel macOS, repeated/missing flags, and settings help.
Validation on the Intel maintainer host:
bun run check: cleanbun test test/unit/: 722 pass, 18 platform skips, 0 fail- live CHR
start-stopunder forced TCG: pass (36.9 s) - live CHR
start-stopunder Intel auto/HVF: pass (24.1 s)
Release boundary: I would not publish the new release until one native Apple Silicon run confirms the actual quickchr path: default arm64 start emits -accel tcg,tb-size=256 and boots, while --accel hvf reaches QEMU (and is expected to retain the current-image panic caveat). The artifact/source evidence is strong, but this repo's own Apple Silicon launch path still has no live run.
Larger follow-ups, not folded into this PR:
- Update
tikoci/routeros-skillsbefore or with the release. The publicrouteros-qemu-chracceleration example still allows matching arm64/HVF and does not record the CHR AArch32 artifact constraint;routeros-quickchralso carries the older acceleration boundary. - Decide whether
default-arch=autounder Rosetta should mean the physical arm64 host instead of the translated process's x86 architecture. This PR now chooses the correct x86/TCG accelerator, but changing the default guest architecture also touches wizard/default semantics, binary/firmware resolution, and needs a real Apple Silicon test. - Rewrite or close issue #97 with the corrected AArch32 explanation when this lands; its body still leads with the superseded SSBS theory, while the correction currently lives in a later comment.
All seven bot threads were reviewed, replied to, and resolved. Six findings were fixed. I declined the requested wholesale Node-to-Bun settings I/O rewrite: the synchronous atomic-write implementation predates this split, node:fs/node:path are supported and used throughout this Bun repo, and replacing the fsync/rename sequence is a separate behavioral refactor rather than a correction to this PR.
…ccel override source Review follow-ups on the #97 branch. integration.yml claimed "macos-arm64 macos-15 arm64 CHR HVF" and printed "Accel hint: HVF (expected)" for the macOS legs. Both are false: hosted macos-15 runners are themselves VMs ("Apple M1 (Virtual)") and report kern.hv_support=0, so detectAccel() returns tcg there -- confirmed in run 29669706663's platform log. That mattered while reviewing this branch: a green macos-arm64 leg looks like it validates the HVF path and does not. The header now says so explicitly, and the accel hint defers to the detectAccel line it already logs. accelNote()/doctor said only "configured as X". With three override tiers (--accel > QUICKCHR_ACCEL > quickchr.env), the useful part of that message is which one set it -- a stale `accel=tcg` in quickchr.env is otherwise an unexplained slowdown. resolveAccelOverrideWithSource() reports the tier and the note names it; resolveAccelOverride() keeps its signature. Also fixes a stray indent in start-stop.test.ts. Refs #97 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
@coderabbitai full review |
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@test/unit/platform.test.ts`:
- Around line 494-508: Add the same spawnSync mock used by the “false on an
Intel Mac” isAppleSiliconHost test before the darwin/x64 accelNote("arm64",
"tcg") assertion, ensuring the sysctl probe reports a non-translated Intel host
and the test remains environment-independent.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: d48f037d-76e0-4a9f-96ed-842940efc2fe
📒 Files selected for processing (19)
.github/copilot-instructions.md.github/instructions/qemu.instructions.md.github/workflows/integration.ymlCHANGELOG.mdDESIGN.mdMANUAL.mddocs/m4-hvf-arm64-investigation.mdproject-words.txtsrc/cli/index.tssrc/lib/platform.tssrc/lib/quickchr.tssrc/lib/settings-file.tssrc/lib/settings.tssrc/lib/types.tstest/integration/start-stop.test.tstest/unit/cli-settings.test.tstest/unit/cli-start-flag-resolution.test.tstest/unit/platform.test.tstest/unit/settings.test.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
In Bun-based TypeScript code, use
Bun.spawn(),Bun.write(),Bun.sleep(),bun:test, and ESM imports with.tsextensions.
**/*.{ts,tsx}: Use Bun APIs andbun:testrather than Node.js APIs, CommonJS, or other test frameworks; use.tsextensions in ESM imports.
For ARM64 (virt) QEMU machines, never useif=virtiofor drives; use an explicit-device virtio-blk-pci,drive=drive0device instead.
When using HVF acceleration, use-cpu host, notcortex-a710.
For arm64 guests on macOS, automatically select TCG with-cpu cortex-a710;--accelandQUICKCHR_ACCELmust override this behavior for testing.
UEFI pflash code and vars units must be identical in size.
QGA is x86-only; do not start or configure the guest agent for arm64 CHR guests.
Use tabs for indentation and avoid unnecessary comments on obvious code.
ThrowQuickCHRError(code, message, installHint?)for errors.
Files:
test/unit/settings.test.tstest/unit/cli-settings.test.tstest/integration/start-stop.test.tssrc/lib/types.tssrc/lib/settings-file.tssrc/lib/quickchr.tssrc/lib/platform.tssrc/cli/index.tssrc/lib/settings.tstest/unit/cli-start-flag-resolution.test.tstest/unit/platform.test.ts
test/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Do not turn a red integration test green by broadening timeouts, skipping it, or platform-gating it before reproducing and root-causing the failure.
Files:
test/unit/settings.test.tstest/unit/cli-settings.test.tstest/integration/start-stop.test.tstest/unit/cli-start-flag-resolution.test.tstest/unit/platform.test.ts
test/unit/**/*.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Unit tests must be fast and must not require QEMU.
Files:
test/unit/settings.test.tstest/unit/cli-settings.test.tstest/unit/cli-start-flag-resolution.test.tstest/unit/platform.test.ts
**/*.{md,ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Keep the
routeros-qemu-chrandrouteros-quickchrshared skills synchronized with quickchr behavior; keepSKILL.mdandreferences/quickchr-api.mdaligned with the repository.
Files:
test/unit/settings.test.tstest/unit/cli-settings.test.tstest/integration/start-stop.test.tssrc/lib/types.tssrc/lib/settings-file.tsCHANGELOG.mddocs/m4-hvf-arm64-investigation.mdsrc/lib/quickchr.tsMANUAL.mdsrc/lib/platform.tssrc/cli/index.tsDESIGN.mdsrc/lib/settings.tstest/unit/cli-start-flag-resolution.test.tstest/unit/platform.test.ts
test/integration/**/*.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Integration tests require QEMU and must be guarded by
QUICKCHR_INTEGRATION=1.
Files:
test/integration/start-stop.test.ts
src/**
📄 CodeRabbit inference engine (CLAUDE.md)
Follow the rules in
general.instructions.mdfor files undersrc/**, including layer boundaries, error-code usage, port layout, and the RouterOS “expired admin” caveat.
Files:
src/lib/types.tssrc/lib/settings-file.tssrc/lib/quickchr.tssrc/lib/platform.tssrc/cli/index.tssrc/lib/settings.ts
src/lib/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Keep
src/lib/as pure library code: do not import fromsrc/cli/and do not callprocess.exit()there.Keep
src/lib/modules pure: do not add CLI dependencies or callprocess.exit().
Files:
src/lib/types.tssrc/lib/settings-file.tssrc/lib/quickchr.tssrc/lib/platform.tssrc/lib/settings.ts
src/cli/**/*.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Keep
src/cli/as a thin wrapper over the library.
Files:
src/cli/index.ts
🧠 Learnings (1)
📚 Learning: 2026-07-27T03:48:25.618Z
Learnt from: mobileskyfi
Repo: tikoci/quickchr PR: 99
File: src/lib/settings-file.ts:13-31
Timestamp: 2026-07-27T03:48:25.618Z
Learning: For TypeScript files in src/lib/settings*.ts (notably src/lib/settings.ts and src/lib/settings-file.ts), treat the existing settings subsystem contract as intentional: it uses synchronous node:fs/node:path with the established atomic fsync/rename write sequence. When reviewing changes—especially the extraction of read-only quickchr.env handling into src/lib/settings-file.ts—avoid requesting a Bun-native filesystem conversion as part of that extraction, unless a dedicated behavioral refactor is explicitly in scope. Keep the extraction focused on breaking the import cycle (leaf-module structure), not changing IO semantics.
Applied to files:
src/lib/settings-file.tssrc/lib/settings.ts
🔇 Additional comments (19)
.github/copilot-instructions.md (1)
46-46: LGTM!.github/instructions/qemu.instructions.md (1)
30-39: LGTM!Also applies to: 92-98
.github/workflows/integration.yml (1)
25-36: LGTM!Also applies to: 313-316
CHANGELOG.md (1)
11-21: LGTM!Also applies to: 22-43, 44-47
DESIGN.md (1)
57-63: LGTM!Also applies to: 111-134
MANUAL.md (1)
401-412: LGTM!Also applies to: 421-429, 932-945, 1009-1009, 1021-1021
docs/m4-hvf-arm64-investigation.md (1)
576-615: LGTM!project-words.txt (1)
275-275: LGTM!Also applies to: 430-430
test/integration/start-stop.test.ts (1)
9-9: LGTM!Also applies to: 36-37, 78-78
src/lib/types.ts (1)
16-37: LGTM!src/lib/settings-file.ts (1)
1-52: LGTM! Extraction correctly preserves the existing file-tier contract as a leaf module.Based on learnings, the synchronous
node:fs/node:pathimplementation here is an established, intentional contract for this extraction — not flagging a Bun-native I/O conversion.Source: Learnings
src/lib/settings.ts (1)
16-25: LGTM!Also applies to: 100-110, 126-126, 140-141, 161-213
test/unit/cli-settings.test.ts (1)
51-76: LGTM!test/unit/settings.test.ts (1)
296-299: LGTM!src/lib/platform.ts (1)
6-10: LGTM! Override precedence, Apple Silicon detection, and the arm64/x86 TCG fallback logic on macOS are correct and consistent with the documented policy.Also applies to: 117-121, 142-261, 279-305
test/unit/platform.test.ts (1)
1-1: LGTM! Setup/teardown correctly pins the accel override and Apple Silicon cache per test, and the new detectAccel/isAppleSiliconHost/override suites all match the implementation.Also applies to: 12-17, 65-76, 328-339, 371-404, 417-482
src/cli/index.ts (1)
160-179: LGTM!Also applies to: 558-558, 1199-1200, 2746-2748, 2831-2833, 3088-3089
src/lib/quickchr.ts (1)
29-29: LGTM!Also applies to: 1529-1530, 1843-1844, 2008-2015
test/unit/cli-start-flag-resolution.test.ts (1)
4-19: LGTM!Also applies to: 30-30, 140-152
…ertion CodeRabbit finding on #99. accelNote("arm64","tcg") with platform=darwin, arch=x64 reaches isAppleSiliconHost(), which is the one branch that shells out to `sysctl -n sysctl.proc_translated`. That assertion installed no mock, so it ran the real probe: it passed on an Intel host for the wrong reason, and on an Apple Silicon host running the suite under Rosetta the probe answers "1", isAppleSiliconHost() returns true, and the expected null becomes a note. Demonstrated with a preload that answers proc_translated=1 for any unmocked probe -- the assertion fails before this change and passes after, and the rest of the suite (740 tests) is unaffected, confirming this was the only site. Every other darwin+x64 test already mocks the probe. Refs #97 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…enum Copilot finding on #99. doctor's Acceleration row printed the raw AccelOverrideSource discriminant -- "configured override (env)" -- while accelNote() printed the user-facing name. The row is meant to tell you what to go edit, so the enum is the wrong string and the two surfaces disagreed. accelSourceLabel() is now exported and shared by both, and its file-tier label is shortened to "quickchr.env" so it reads correctly in either sentence. Both now say --accel / QUICKCHR_ACCEL / quickchr.env. Adds doctor --json coverage that the row names the source and contains no "(flag)"/"(env)"/"(file)" enum text, plus that an unconfigured host gets no override suffix at all -- verified to fail against the previous behavior. runQuickchr() now drops an inherited QUICKCHR_ACCEL so a developer with an accelerator forced in their shell doesn't fail the unconfigured case. Refs #97 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Refixes #97. The
FEAT_SSBS=0 → TCGfallback merged in #98 keyed on the wrong axis. It is still unreleased (last tagv0.4.5), so this corrects it in place rather than deprecating it.SSBS was a coincident marker, not the mechanism
M4 is the first Apple chip to report
hw.optional.arm.FEAT_SSBS = 0, which is why the reporter's diagnostics correlated. But Linux 5.6 treats SSBS as an optional mitigation and boots fine without it —cortex-a53andneoverse-n1don't implement it either. SSBS-absence cannot produceNo working init found.Actual root cause: the CHR image requires AArch32, Apple Silicon has none
Current arm64 CHR images pair an AArch64 kernel with a 32-bit ARM userspace:
/inittypeELF 32-bit LSB ARM, EABI5, staticELF 32-bit LSB ARM, EABI5, staticELF 32-bit LSB ARM, EABI5, staticThe 7.22.1
systempackage holds 101 more ARM32 executables and 18 ARM32 shared objects; the only AArch64 executables arekexecandvmcore-dmesg. An AArch64/initalone would not fix it — the failure would just move later.Apple Silicon implements no AArch32 at any exception level (
ID_AA64PFR0_EL1is AArch64-only for EL0/EL1), and QEMU under HVF passes that hardware register straight through —hvf_arch_init_vcpu()re-reads the live vCPU register and edits only the GIC bit, so the-cpumodel is inert. The guest kernel never setsARM64_HAS_32BIT_EL0,compat_elf_check_arch()rejects theEM_ARM/initwith-ENOEXEC, the initramfs has no fallback init, and Linux panics at t≈0.076 s.Confirmed by the guest's own panic-time capability bitmap, decoded against Linux 5.6
cpucaps.h(ARM64_HAS_32BIT_EL0 == 13):ARM64_HAS_32BIT_EL0-accel hvf -cpu host— panics0x20012,28000230-accel tcg -cpu cortex-a710— boots0x20013,28402230The failing set is a strict subset; the only other differences are
ARM64_SVEandARM64_HAS_STAGE2_FWB, neither of which participates inexecve().Consequences for the fix
Hypervisor.frameworkexposes onlyhv_vcpu_config_get_feature_reg()— there is no setter — so no macOS VMM can present a feature the silicon lacks (UTM's fork behaves identically). The deferredgetQemuVersion()guard is dropped, not postponed./initand required system-package executables/shared objects are all AArch64, confirmed by a real HVF boot. That check is mechanical and could become a release-time guard.Full chain, evidence table, and reproduction:
docs/m4-hvf-arm64-investigation.md. Reported upstream to MikroTik (request: ship an ARM32-free arm64 userspace, or document that the image requires AArch32 EL0 despite its AArch64 kernel).Second bug found while fixing this: x86 CHR was broken on Apple Silicon
Not a slowdown — a hard failure, pre-existing and unrelated to SSBS.
detectAccel("x86")returnedhvfwheneverkern.hv_support=1, including on Apple Silicon, soqemu-system-x86_64was launched with-accel hvfon an arm64 host. HVF is compiled into a QEMU binary only when the emulated target matches the physical host, so that binary has nohvfaccelerator at all and QEMU exits.Verified by the mirror-image test on an Intel Mac, where the same asymmetry is observable locally:
detectAccelnow selects TCG for both guest arches on Apple Silicon, andisAppleSiliconHost()usessysctl.proc_translatedso a Rosetta process (which reportsprocess.arch === "x64") is still recognized as an arm64 host.isCrossArchEmulation()became symmetric as a result, so x86-on-arm64 finally gets the cross-arch timeout factor.Repo docs already disagreed with the code here —
qemu.instructions.mdsaid x86 CHR "must useaccel=tcg" on Apple Silicon whileDESIGN.md's table claimed HVF. The table was wrong; both now match the code.Changes
detectAccel("arm64")returnstcgon all macOS hosts.hostLacksSsbs()/ssbsTcgWarning()→isAppleSiliconHost()/accelNote().--accel <auto|tcg|hvf|kvm>onstart/add, plus anaccelsetting andQUICKCHR_ACCELenv var (precedence: flag > env >quickchr.env>auto, matching every other setting). Anything butautois passed to QEMU verbatim and bypasses detection entirely, so HVF can be tested against a future AArch64-only image with no code change. Forcing--accel hvffor an arm64 guest on Apple Silicon still prints the panic caveat rather than obeying silently.doctormarks the acceleration row when an override is in effect (otherwise the row reads as a capability report it isn't), and the launch note names the tier that set the accelerator (--accel/QUICKCHR_ACCEL/quickchr.env) — a staleaccel=tcgin the settings file is otherwise an unexplained slowdown.integration.yml's header claimedmacos-arm64 → arm64 CHR HVFand printedAccel hint: HVF (expected). Both were false and are corrected — see Verification.DESIGN.mdfix(ci): kill orphaned QEMU processes on macOS-x86 step timeout to prevent runner death #10,CHANGELOG.md(replaced the unreleased SSBS entry rather than stacking a correction on it),MANUAL.md,.github/instructions/qemu.instructions.md,.github/copilot-instructions.md, and the investigation doc's implications section.One structural change worth a look
Wiring
platform.tstosettings.tscreated an import cycle (settings → cache → state → network → platform) that loaded eagerly on every CLI start and pushedcli-settings.test.tspast its 5 s timeout. Thequickchr.envfile tier is extracted into a leaf modulesrc/lib/settings-file.ts(node:fs + paths.ts only);settings.tsre-exports it, so the public API is unchanged.platform.tsimports the leaf, notsettings.ts.Verification
Local (Intel x86_64 Mac):
bun run checkclean — Biome,tsc --noEmit, markdownlint, cspell, examples, shellcheck.bun test test/unit/— 719 pass, 18 skip, 0 fail.-accel hvf) and--accel tcg(-accel tcg,tb-size=256), confirming the override reaches QEMU's argv and the launch path is intact.process.platform/process.arch.QUICKCHR_INTEGRATION=1 bun testoverstart-stop,library-api,forward-cli,settings-secure-login-cli— 14 pass, 0 fail (326 s, real CHR boots).CI cannot validate the HVF path, and its docs claimed otherwise. The
macos-arm64gating leg runs on hostedmacos-15runners that are themselves VMs (Apple M1 (Virtual)) reportingkern.hv_support=0; its own platform log readsquickchr detectAccel(arm64): tcg(run 29669706663). So that leg has never exercised arm64 HVF, and a green macOS run is not evidence about #97 either way. The workflow header said it was HVF; that's fixed in this PR so the next reader isn't misled.Grounding boundary, unchanged and important: this is not reproduced locally — dev and CI hosts are Intel x86_64, and the failure needs Apple Silicon. The M4 evidence is the reporter's (tikoci/mikropkl#11), and the exact
Failed to execute /init (error -8)line remains unobserved. What's verified here is accelerator selection, the override, and the x86 boot path. A reviewer on Apple Silicon confirming that--accel hvfon an arm64 guest still panics — and that the default TCG path boots — would close the last gap.Refs #97. Downstream: tikoci/mikropkl#11.
🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
--acceloption,QUICKCHR_ACCEL, and theaccelsetting.Bug Fixes
Documentation