Files
chanora/tools/windows-smoke.md
EdisonJwa 21945979a3 test(audio,ptt): comprehensive Windows P0 unit-test suite (L0-L11)
Layered test coverage for the Windows PTT subsystem ahead of the
v1.0.0-rc.8 official release sign-off.

L0 (refactor)
- Extract three pure-logic dispatchers from the existing WndProc /
  LowLevelKeyboardProc / LowLevelMouseProc bodies in
  crates/chanora_audio/src/ptt_backends/windows.rs:
    dispatch_raw_input(ctx, &RAWINPUT)
    dispatch_hook_keyboard(ctx, wparam, &KBDLLHOOKSTRUCT)
    dispatch_hook_mouse(ctx, wparam, &MSLLHOOKSTRUCT)
  Each takes a small Context (AtomicBinding + AudioTransmitGate +
  flags) and is callable without spinning up any Win32 plumbing.
  The real Win32 procs unchanged structurally; they unpack lparam
  and forward to the dispatchers. AtomicBinding / RawInputContext
  / HookContext / resolve_binding are now pub(crate) so the
  in-file test module can drive them.

L1 — windows_keymap full-table sweep (+13 tests)
  Every key_label_to_vk arm, all A-Z + a-z, all 0-9, F1-F20,
  navigation, modifiers, OEM punctuation, numpad. Exhaustive
  mouse_label_to_button cases including the 0x08 / 0x10 /
  unknown-bitmask fallbacks.

L2 — AtomicBinding lock-free correctness
  store/read round-trip, clear(), Default = zeros, single-writer
  / single-reader concurrency, many-readers / single-writer.

L3 — resolve_binding dispatcher tests
  All PttInputClass variants, well-known labels, unknown-label
  fallback, mismatched class+label rejection, mouse bitmask
  resolution.

L4 — Backend state-machine
  Both WindowsRawInputBackend and WindowsHookBackend:
  descriptor() pre-arm vs post-arm (L0Focused -> L2/L3), start()
  with None binding rejection, rebind() in-place, stop()
  clears + idempotent, stop() after stop() no-op.

L5 — dispatch_raw_input table
  Keyboard match/non-match, key-down/key-up via Flags & 0x01,
  no-binding short-circuit, mouse XBUTTON1/XBUTTON2 down/up
  matching the bound button, unhandled HID type. RAWINPUT structs
  built via mem::zeroed plus field-fill, owning the unsafe in
  the test layer where it belongs.

L6 — dispatch_hook_keyboard + dispatch_hook_mouse
  WM_KEYDOWN / WM_KEYUP / WM_SYSKEYDOWN / WM_SYSKEYUP for the
  keyboard path, WM_XBUTTONDOWN / WM_XBUTTONUP for the mouse
  path. Same shape as L5.

L7 — Privacy invariant (crates/chanora_audio/tests/ptt_privacy.rs)
  New cross-platform integration test installs a custom
  tracing_subscriber Layer that records every emitted event's
  target + field names. Exercises the public PTT API plus (on
  Windows) the backend factory. Asserts no field name in the
  banned list (vk, scan_code, keysym, key_label, bound_key,
  binding, platform_key, VKey, wVk, wScan, kbflags, mouseflags)
  is ever emitted and every field belongs to the DEC-027
  allow-list. Adds tracing-subscriber as a dev-dependency on
  chanora_audio.

L8 — Full-chain integration in core/chanora_core/src/ptt.rs
  Windows-only mod windows_full_chain_tests:
    zero-tail full chain (synchronous)
    default-tail full chain (200 ms wait then off)
    mid-press rebind abandons in-flight press

L9/L10/L11 — tools/windows-smoke.cmd + tools/windows-smoke.md
  Batch smoke script + operator doc. cargo build, flutter build,
  artifact existence + size checks, headless launch with stderr
  capture, bridge-initialised log assertion. Distinct exit codes
  per failure step. Doc explains invocation + common failure
  modes.

Verification (Linux)
- cargo check --workspace: clean.
- cargo test --workspace: 78 passed / 0 failed / 3 ignored.
  76 cross-platform unit tests (unchanged) plus the new
  ptt_privacy integration test plus one new ignored portal smoke
  test.

The Windows-gated tests (~49 new) compile and run on the Korean
Windows 11 host where they belong; cross-compile from Linux is
not configured locally. The smoke script is the production
acceptance gate for rc.8 on Windows.

Deviations from the original plan are minor (single ignored
real-runtime test rather than per-platform attribute, L7 uses
public API rather than pub(crate) dispatchers, dispatchers live
inside windows.rs rather than a sibling module) and documented
in the subagent report.
2026-05-16 00:47:10 +08:00

84 lines
3.8 KiB
Markdown

# `tools/windows-smoke.cmd` — Korean host smoke build + launch
End-to-end "does Chanora build and start on Windows" verification.
Designed for the lead's Korean Windows 11 test host and the
`product/scaffold-v0` branch. Run from any directory inside the
checked-out repo:
```
C:\Users\admin\chanora> tools\windows-smoke.cmd
```
The script `pushd`'s to the repo root (resolved from its own
location), so the working directory does not matter as long as
the script lives in `tools\` inside the checkout.
## What it does
1. Prepends Flutter + Cargo + MSVC to `PATH` and runs
`vcvars64.bat`. Hard-coded paths assume the Korean host
layout. If a path changes, edit the `set "PATH=..."` and
`call "...\vcvars64.bat"` lines near the top.
2. `cargo build -p chanora_bridge --release` and checks
`target\release\chanora_bridge.dll` exists and is at least
5 MB.
3. `flutter build windows --release` inside `apps\chanora_flutter`
and checks the runner + `data\app.so`.
4. Copies the bridge DLL into the Flutter release folder.
5. Launches the runner for five seconds with stderr redirected to
`%TEMP%\chanora-smoke.log`, then kills it.
6. Greps the log for `bridge initialised` (must be present) and
`panicked` (must be absent).
7. Prints `PASS` and exits 0 on success.
## Exit codes
| Code | Step |
| ---- | -------------------------------------------------------------------- |
| 0 | PASS |
| 1 | `vcvars64.bat` failed |
| 2 | `cargo build -p chanora_bridge --release` failed |
| 3 | bridge DLL missing or smaller than 5 MB |
| 4 | `flutter build windows --release` failed |
| 5 | `chanora_flutter.exe` missing |
| 6 | `data\app.so` missing or smaller than 1 MB |
| 7 | bridge DLL copy into the Release folder failed |
| 9 | log did not contain `bridge initialised` (bridge didn't load / panic at init) |
| 10 | log contained `panicked` (Rust panic during the 5 s smoke window) |
## Common failure modes
* **vcvars64 returns non-zero**: MSVC not installed at the
expected path. Update the `call "...\vcvars64.bat"` line or
install the Build Tools workload from the VS2022 installer.
* **`cargo build` fails with `link.exe not found`**: vcvars64
did not take effect. Re-run from a fresh `cmd.exe` (PowerShell
has its own quirks here).
* **Bridge DLL exists but smaller than 5 MB**: a debug build
slipped in. Make sure the script's `--release` flag was
honoured; check that no `[profile.release]` override is
stripping symbols too aggressively.
* **`data\app.so` smaller than 1 MB**: Flutter assets did not
bundle. Run `flutter clean` then re-run the script.
* **`bridge initialised` absent**: the bridge `extern` symbol
is not being found by the Flutter side. Verify the DLL copy
step ran (it did, or the script would have exited 7) and that
the DLL name matches what `lib/main.dart`'s ffi setup expects.
* **`panicked` present**: open `%TEMP%\chanora-smoke.log` (the
script dumps it on failure) and read the panic message. The
most common cause during scaffold development is a missing
flutter-rust-bridge code-gen file; re-run the codegen step
per `docs/release/desktop-build-runbook.md`.
## Manual rerun of just the launch step
The PASS path always tears the runner down. If you want to
inspect the running application after a green smoke pass:
```
target\release\chanora_bridge.dll (already copied into Release\)
apps\chanora_flutter\build\windows\x64\runner\Release\chanora_flutter.exe
```
Launching the EXE directly will reuse the copied DLL.