Per-terminal CLI device pins (retire eval $(device connect)) + CI report/daemon hardening#145
Merged
Conversation
eval \$(device connect)) + CI report/daemon hardening
eval \$(device connect)) + CI report/daemon hardeningeval $(device connect)) + CI report/daemon hardening
handstandsam
added a commit
that referenced
this pull request
Jun 1, 2026
* Stop tracking generated trailmap build artifacts under examples/wikipedia The bundled SDK (`trails/.trailblaze/`) and daemon-compiled target YAMLs (`trails/config/dist/`) are regenerated build output, not source. They were committed in #145 because the OSS .gitignore rules were root-anchored (`/trails/...`) and missed `examples/*/trails/...`. Re-anchor both rules to `**/` to match the internal repo, and drop the artifacts that slipped in. * Upstream sync * CLI output tweaks * alarm clock trail tweak
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The headline change moves device pinning away from the
eval $(trailblaze device connect …)env-var dance to per-terminal, file-based device pins. Also bundled: CI report generation driven entirely off the prebuilt uber JAR, a bounded Playwright video finalizer, a shorter daemon run-poll timeout, and a regression test for the workspace trailmap-shadowing CI hang.Per-terminal device pinning
trailblaze device connectno longer needseval $(...)to exportTRAILBLAZE_DEVICE/TRAILBLAZE_TARGETinto the shell. The binding is now written to a per-terminal pin file (~/.trailblaze/shell-device-pins-<port>.json) keyed by the shell PID thetrailblazewrapper forwards asTRAILBLAZE_SHELL_PID. Subsequent commands in the same terminal inherit the device (and target) automatically; other terminals stay independent.ShellDevicePinStore— a small JSON store mappingshellPid → {device, target}, with kernel-level advisory file locking plus an in-JVM monitor for safe read-modify-write, atomic tempfile + rename writes, lazy GC of dead-PID entries, and port-scoped files for multi-daemon isolation. The liveness probe is injectable so eviction logic is unit-testable.resolveDeviceWithAutodetect:--deviceflag →TRAILBLAZE_DEVICE(manual override) → this terminal's file-pin → single-device autodetect. The pin is validated against the live device list and evicted with a clear message when its device is gone, then falls through to autodetect.--targetis stored alongside the device so it survivestrailblaze app --stop && app startinstead of living only in the daemon's in-memory registry.--target=clearnow also clears the pin's target field (previously only the daemon side was cleared, so the pin silently re-established it).TRAILBLAZE_INTERACTIVEfrom a tty check;device connectwarns non-interactive callers (Claude Code, Cursor, Codex, CI — each command is a fresh shell with a different PID) that the pin won't carry, and points them at--deviceper call.device connect/disconnect/rebindupdated to read and write the pin; disconnect and rebind also resolve the device from the pin when no flag/env is supplied. Legacyeval $(trailblaze device disconnect)keeps working — theunsetlines are still emitted on stdout for users mid-migration, but are now vestigial.trailblaze rungains the file-pin tier sodevice connect Xfollowed byrun …inherits the device. Trails deliberately do not inherit the terminal's target pin — a trail declares its own target to stay deterministic across developers and CI.docs/CLI.mdare rewritten to dropeval $(...); a singleDEVICE_OPTION_DESCRIPTIONconstant now backs the-d/--devicehelp on every action command, and the CLI help baselines are regenerated.CI report generation off the prebuilt uber JAR
Both
pr_generate_trailblaze_report.shandpr_generate_report_assets.shnow drive thetrailblaze reportCLI off the prebuilt uber JAR — which already bundles the WASM report template (thebuild-uber-jarjob invokes Gradle with-Ptrailblaze.wasm=true). This drops the separate:trailblaze-ui:wasmJsBrowserProductionWebpack/:trailblaze-report:run/generateReportTemplateGradle steps. The index script renamesreport.html→trailblaze_report.htmlin place so downstream artifact/upload paths stay unchanged.Daemon / capture hardening
PlaywrightVideoRecordDir.runFinalizer) now runs on a bounded single-thread daemon executor with a 30s timeout. A wedged Playwright-affinity dispatcher can no longer deadlock the daemon's run-status pipeline (the historical 1800s-timeout symptom); on timeout we drop the in-flight flush and fall back to the on-disk.webm.Tests
ShellDevicePinStoreTest— cold-start, set→resolve round-trip, dead-PID eviction, concurrent terminals coexisting, opportunistic GC, concurrent-writer file locking, port scoping, and corrupted-file tolerance.AppTargetDiscoveryTest— regression for the OSS CI hang: a cwd workspace that owns a collidingwikipediatrailmap id must not shadow theTRAILBLAZE_CONFIG_DIR-pointed workspace's target and YAML tools.DaemonClientPollResilienceTest— comment updated for the new poll timeout.