Skip to content

fix(native): SIGTERM orderly exit, acceptance --dry-run, and real-desktop driver recipes (#328, #329) - #330

Merged
turinglambdaai merged 2 commits into
mainfrom
fix/native-ui-recipes-328-329
Oct 26, 2026
Merged

turinglambdaai merged 2 commits into
mainfrom
fix/native-ui-recipes-328-329

Conversation

@turinglambdaai

Copy link
Copy Markdown
Owner

Summary

Fixes the implementation deliverables of #328 and #329 (both sourced from the #314 real-product journeys). Docs, the reference driver, a new CLI capability, and one runtime-behavior fix with red-green proof.

SIGTERM orderly exit (#329, finding 2)

The embedded Racket CS runtime maps SIGTERM to a Racket break; a GUI host swallows that break, so a packaged app hangs forever when terminated. Reproduced deterministically on a healthy packaged app (this is not only the wedged-startup case), while a plain racket process exits because its top level lets the break propagate.

The macOS host template (and the reference taskboard example) now install a self-pipe SIGTERM handler whose main-queue dispatch source runs NSApplication.terminate — reusing the existing applicationShouldTerminate orderly stop. The handler is installed at launch and re-asserted after the backend starts, because the runtime boot installs its own handlers and the last installation must win.

Red-green evidence: packaged app from the old template survived kill -TERM (still running at 0.0% CPU minutes later); packaged app from the new template exited orderly ~1 second after kill -TERM.

raco rivet acceptance --dry-run (#328, finding 3)

Loads and validates the manifest (shape, requirement coverage), resolves the current platform's suites and their executables, checks evidence path rules, and exits before launching any child. A hand-edited manifest with a syntax error now fails in seconds with a precise read error instead of minutes into a packaged suite. The report is flagged "dry-run": true with per-suite "dry-run" statuses — a validation record that must not feed raco rivet matrix. Tests cover the green path, no-execution proof, parse failure, missing executable, and evidence-path rejection.

Reference driver + docs (#328 findings 1–2, #329 findings 1–3)

native-ui-testing.md now documents the four silent desktop failures and the real exit contract:

  1. AX focus writes are not focus — verify focus actually moved (or require an explicit key-view loop for toolbar-hosted fields).
  2. IMEs swallow synthetic text — TIS ASCII-layout switch around keyboard phases, restore afterwards; helpers shipped in the reference driver.
  3. Posted keys route to the user on shared desktops — frontmost guard before every posted key, fail fast (keyboardGuard in the reference driver).
  4. AX elements die with their views — re-find from the live tree inside every bounded wait; the reference driver's event polling now re-probes instead of caching.
  5. Exit semantics — quit Apple Event is the reliable orderly exit; SIGTERM/terminate/close-button can all be swallowed; second instances report false-positive frontmost with broken key routing. The reference driver exits through Cmd+Q (quitOrderly).
  6. Wedged startup — the spin signature (backend answers, window never renders, threads at full CPU) with one bounded relaunch as the mitigation; wedges are runtime defects to report, never self-healing.

Validation

  • raco test rivet/ rivet-cli/: 10205 passed (includes 6 new dry-run tests).
  • raco test rivet/tests/documentation.rkt: 732 passed.
  • swiftc -typecheck rivet/tests/native-ui/macos-ax.swift: green.
  • raco rivet build in examples/taskboard: green (host template change compiles).
  • SIGTERM red-green executed against freshly packaged scaffold apps (old template red, new template green).
  • --dry-run smoke on a real project: valid manifest → exit 0 with per-suite listing; broken manifest → precise read error, exit 1.

Scope note

#329's startup-spin heisenbug is not fixed here (cannot be reproduced on demand; static analysis points at a GC thread-suspension rendezvous class of race inside the embedded Chez runtime — needs a spindump from a wedged instance). The issue keeps that finding open with the documented mitigation and the diagnostic evidence path; SIGTERM and the exit-semantics findings are resolved by this PR.

…top driver recipes hold on real hosts (#328, #329)

Two real-product journeys (#314) left findings this change closes.

SIGTERM orderly exit (#329): the embedded Racket CS runtime maps SIGTERM to
a Racket break, which a GUI host swallows - a packaged app then hangs
forever when a process manager or suite terminates it (reproduced
deterministically on a healthy app; plain racket exits). The macOS host
template and the reference taskboard now install a self-pipe SIGTERM
handler whose main-queue dispatch source performs NSApplication.terminate,
reusing the existing applicationShouldTerminate orderly stop. Installed at
launch and re-asserted after backend start so the runtime boot cannot
leave its own handler in charge. Red-green: a packaged app from the old
template survives SIGTERM; one from the new template exits orderly in
about one second.

acceptance --dry-run (#328): validates the manifest shape and requirement
coverage, resolves the current platform suites and their executables, and
checks evidence path rules before launching any child, so a hand-edited
manifest fails in seconds instead of minutes into a packaged suite. The
report is flagged dry-run with per-suite dry-run statuses and must not
feed the cross-platform matrix.

Reference driver and docs (#328, #329): the macOS launch orchestration now
states the real exit semantics (quit Apple Event; SIGTERM/terminate/close
button can all be swallowed), warns against keyboard phases in a second
instance (false-positive frontmost, broken key routing), and documents the
four silent desktop failures: AX focus writes that do not move focus, IMEs
swallowing synthetic text (TIS ASCII-layout switch with restore),
posted keys routing to the user on shared desktops (frontmost guard, fail
fast), and AX element zombies after view rebuilds (re-find from the live
tree in every bounded wait). The reference driver gains keyboardGuard,
TIS input-source switching, the quit-Apple-Event exit, and live-tree
re-probing in its event polling; the wedged-startup signature and one
bounded-relaunch mitigation are documented.
The runner's current platform resolves the suites, so the manifests these
tests drive through run-acceptance-command must apply everywhere CI runs
them (linux legs failed the platform-resolution check).
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