Skip to content

test(server): isolate automation registry on Linux - #671

Merged
shantur merged 1 commit into
devfrom
fix/linux-automation-registry-test
Sep 6, 2026
Merged

test(server): isolate automation registry on Linux#671
shantur merged 1 commit into
devfrom
fix/linux-automation-registry-test

Conversation

@pascalandr

Copy link
Copy Markdown
Contributor

Summary

  • isolate the Developer Mode automation registry test on Linux as well as Windows
  • derive the seeded registry path through the production resolver
  • restore LOCALAPPDATA, XDG_RUNTIME_DIR, and WSL_DISTRO_NAME after the test

Root cause

Both final CI runs for #647 failed in prunes stale registry pressure before limiting discovery. The test redirected only LOCALAPPDATA, which Linux ignores, then wrote fixtures into a hard-coded Windows registry path that did not exist.

Validation

  • node --import tsx --test packages/server/src/opencode/automation-plugin.test.ts
  • 20 repeated targeted runs
  • npm run typecheck --workspace @neuralnomads/codenomad
  • git diff --check

This fixes the deterministic Linux failure from PR Build Validation runs 33862538051 and 33863984160.

The stale-registration pressure test only redirected LOCALAPPDATA, which has no effect on Linux. CI therefore published the live bridge in the Linux registry but attempted to seed stale registrations in a missing Windows-style directory.

Redirect both supported registry roots to the test temp directory, disable WSL secondary discovery for the test, derive the directory through the production resolver, and restore every environment variable during cleanup. This keeps the test hermetic on Windows, Linux, macOS, and WSL.

Validated with the eight automation-plugin tests repeated twenty times, the server TypeScript check, and git diff checks. The original Linux CI failure was reproduced from both failed #647 runs.
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown

PR builds are available as GitHub Actions artifacts:

https://github.com/NeuralNomadsAI/CodeNomad/actions/runs/33866655912

Artifacts expire in 7 days.
Artifacts:

  • pr-671-fc20672975305ec65d2f3aa20ff56029463acfea-tauri-macos
  • pr-671-fc20672975305ec65d2f3aa20ff56029463acfea-tauri-macos-arm64
  • pr-671-fc20672975305ec65d2f3aa20ff56029463acfea-electron-macos
  • pr-671-fc20672975305ec65d2f3aa20ff56029463acfea-tauri-linux
  • pr-671-fc20672975305ec65d2f3aa20ff56029463acfea-tauri-windows
  • pr-671-fc20672975305ec65d2f3aa20ff56029463acfea-electron-linux
  • pr-671-fc20672975305ec65d2f3aa20ff56029463acfea-electron-windows

@pascalandr pascalandr left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gatekeeper review of fc206729

No blocking code findings remain.

The change isolates the failing stale-registry case across Windows, native Linux, and WSL by pinning both LOCALAPPDATA and XDG_RUNTIME_DIR, clearing WSL_DISTRO_NAME, deriving the production-selected registry directory, and restoring every environment variable in finally.

Validation

  • PR Build Validation is green on Linux and Windows, including the complete server test suite and the Tauri crate.
  • PR artifact builds are green on every required desktop target.
  • The branch contains one focused test-only change and git diff --check is clean.

Verdict

Gatekeeper-approved. Repository policy still requires an approving review from a reviewer with write access; that is the only remaining merge blocker.

@pascalandr pascalandr assigned pascalandr and shantur and unassigned pascalandr Sep 6, 2026
pascalandr added a commit to pascalandr/CodeNomad that referenced this pull request Sep 6, 2026
Complete NeuralNomadsAI#676's worker-only fix by reading native geometry before any client-state mutex and queueing only the latest capture per known window. Move/resize/DPI and zoom handlers no longer wait on atomic publication, and restore seeds clamped normal bounds before maximization. Ownership validation also leaves the in-memory mutex free during disk reads.

Merge captures under the serialized writer before rollback snapshots. Preserve admission during tentative clear, disable and removal so failed publication cannot lose concurrent events; discard those speculative events after a successful destructive commit. Close admission before draining, retry previously merged but unpublished captures, and retain cross-host fencing until final persistence completes.

Keep a single lazy worker and capacity-one queue, but consume callback ownership while idle and release the scheduler mutex before joining. Concurrent stop callers wait for the same drain while late UI submissions return promptly.

Add sixteen Rust regressions beyond the original three scheduler tests, an Electron parity test, and an independent macOS ARM64 CI test gate. Windows validation passes all 158 Rust tests at default parallelism, all 190 Electron tests, UI/Electron typechecks and a release build. The same source-extraction harness that reproduces the old disk/UI lock failures now passes all five assertions over ten repetitions. Linux CI still depends on the separate NeuralNomadsAI#671 registry fix; an interactive macOS smoke test remains necessary.
pascalandr added a commit that referenced this pull request Sep 6, 2026
Complete #669's compatibility diagnosis without blocking the shared backend while checking a selected executable. Run bounded asynchronous version/help subprocesses and require positive service command evidence, rather than accepting arbitrary exit-zero output. Keep the updater's independent version-only contract and custom version labels unchanged.

Recognize legacy root help from successful wrappers as well as failed status commands on host and WSL. Revalidate explicit binary additions even when an older version is cached, and match the launch-error marker precisely so ordinary missing-file and configuration diagnostics cannot be hidden by a matching path.

Add real subprocess and HTTP regressions for backend responsiveness, read-only validation, quoted/Unicode paths, stdout/stderr and exit codes. Cover capability parsing, execution failures, updater behavior and unrelated launch errors; add a focused Linux/Windows/macOS ARM64 CI matrix without folding in #671's separate registry fix.

Validation: 391 server tests passed with 2 skipped, 189 Electron tests passed, and 79 focused tests passed on Windows. Server/UI/Electron typechecks, production server/UI builds and diff/workflow checks pass. Real V1 1.18.25 is rejected and V2 beta 19151/19192 connects to the existing authenticated service without changing the daemon. Negative controls reproduce the published head's missed diagnostics, cached-version bypass and synchronous probe stall. Interactive Electron/macOS verification remains outstanding.
shantur pushed a commit that referenced this pull request Sep 6, 2026
## Summary

Closes #676.

This PR now addresses both mechanisms behind the window-state hang,
rather than only reducing the thread count:

- one lazy named worker, a capacity-one wakeup queue, and a 250 ms
debounce;
- native getters run before **any** client-state lock, including
explicit close/shutdown captures;
- move/resize/scale-factor/zoom handlers enqueue only the latest
geometry per known window and never acquire the disk writer lock;
- serialized publication merges queued captures, preserves normal bounds
across maximize/fullscreen, and seeds clamped restore bounds before
maximizing;
- rollback preserves events arriving during
snapshot/clear/disable/removal publication, including the window whose
policy is tentatively changing; a successful destructive commit discards
those speculative events;
- shutdown closes capture admission, joins the worker without retaining
the scheduler/writer mutex, drains an omitted wakeup, and retries
captures merged by a failed flush before ownership release;
- no application handle retained by the idle worker;
- ownership-file validation in `load_window` moved outside the shared
in-memory state lock.

Electron already debounces native geometry; its production code is
unchanged, with a new parity regression covering bursts, maximization,
explicit flush, and closed-window cleanup.

## Why the initial version was insufficient

The original head `bb38b1a2` fixed thread proliferation, but
`capture_window_in_memory` still held `write_lock` across native
getters. A slow fsync could block the UI through that mutex; a
secondary-thread capture could also hold it while waiting for the same
UI thread that was handling a move/resize event.

This follow-up retains the useful scheduler behavior and completes the
capture/persistence separation in the same PR. No competing #676 PR is
being introduced.

## Before/after evidence

An external Rust harness compiles the exact production capture, flush,
release and scheduler function bodies, replacing only the native/disk
adapters. It counts real Windows OS threads and uses controlled channel
gates rather than relying on a randomly timed freeze.

| Assertion | Base `52f0e629` | Initial PR `bb38b1a2` | Completed PR |
| --- | --- | --- | --- |
| 128 flush requests | +128 threads | +1 thread | +1 thread |
| Capture completes before blocked disk publication is released | FAIL |
FAIL | PASS |
| UI can complete move/resize while a secondary capture waits for a
native getter | FAIL | FAIL | PASS |
| Explicit capture/flush retains geometry | PASS | PASS | PASS |
| Future envelopes and ephemeral windows remain protected | PASS | PASS
| PASS |

Ten repetitions per compared version produced the same outcomes. This is
a controlled reproduction of the concurrency mechanisms, not a claim of
having run the reporter's macOS GUI session.

## Committed regression coverage

The crate now includes **19 focused scheduler/capture tests** (the
original three plus sixteen additional regressions), using the actual
`ClientState`, native-read seam, scheduler and atomic-write adapter.
Coverage includes:

- 1,000 captures during a stalled disk write; bounded memory and latest
geometry;
- no client-state mutex held by native getters; simulated secondary
getter/UI event cycle;
- one worker/one trailing wakeup, callback lifetime, concurrent stop,
cheap late submission and no restart after release;
- independent windows, maximization/fullscreen, zoom, unknown-window
rejection;
- successful and failed destructive publication, simultaneous events on
the mutating and another window, retry after failed flush;
- final persistence and cross-host ownership handoff;
- secondary ownership and future-envelope fencing.

## Validation

- Full Windows Tauri crate: **158 tests passed**, including default test
parallelism.
- Electron native suite: **190 tests passed**.
- UI/Electron typechecks passed.
- Official Tauri resource preparation and server/UI builds passed during
verification.
- Windows release executable builds successfully.
- `cargo fmt --check`, `git diff --check`, and workflow YAML parsing
passed.
- Added an independent **macOS ARM64 (`macos-26`) Tauri test job** to
exercise the crate on the reported platform; packaging now depends on it
as well. Its remote result must be checked before merging.

## CI dependency and limits

The inherited Linux automation-registry test failure remains isolated in
**#671**. #675 was closed as its duplicate and is not part of this fix.
No duplicate registry patch or unrelated PR was merged into this branch.
After #671 is integrated, update this branch and require the complete
matrix before merge.

Windows controlled reproductions and tests are not a substitute for a
macOS ARM64 interactive launch/move/resize smoke test. Persistent disk
failures are still logged and cannot guarantee saving to an unavailable
disk. No claim of absolute absence of side effects is made.

Maintenance note: `packages/tauri-app/src-tauri/src/client_state.rs`
remains oversized (about 1,160 lines); focused capture and scheduler
code/tests are kept in sibling modules instead of undertaking an
unrelated refactor.
@shantur
shantur merged commit 81aa4d2 into dev Sep 6, 2026
13 checks passed
@shantur
shantur deleted the fix/linux-automation-registry-test branch September 6, 2026 17:33
pascalandr added a commit that referenced this pull request Sep 6, 2026
Update #672 with dev at 81aa4d2, including the integrated #671 registry isolation, #674 POSIX shell selection and #677 window persistence fixes. This brings in the previously missing Linux CI prerequisite without duplicating its patch.

Resolve the sole conflict in pr-build.yml by retaining both the OpenCode compatibility matrix and macOS ARM64 Tauri test job, and requiring both before packaging. Every non-build job is structurally identical to its originating parent and every parent build dependency is preserved. No application code needed manual conflict resolution.

Validation after integration: 391 server tests passed with 2 skipped, all 192 Electron tests passed, and server/UI/Electron typechecks passed. YAML parsing, exact parent-job comparisons and git diff --check pass. The complete remote matrix must rerun on the combined branch before merging the PR.
pascalandr added a commit that referenced this pull request Sep 6, 2026
## Summary

Closes #669.

CodeNomad V2 requires the official OpenCode V2 shared-service lifecycle.
A legacy binary must not be accepted merely because `--version`
succeeds, nor should opening a folder display a raw legacy CLI help
dump. This is an actionable compatibility fix, **not V1 runtime support
or automatic installation**: install/select `opencode2` to open the
workspace.

- Validate the selected executable using only `--version` and `service
--help`; neither probe starts or changes the daemon.
- Require positive service-help evidence for `start`, `status`, and
`get`, without pinning a release number or rejecting custom version
labels.
- Recognize legacy root help, including ANSI/CRLF, stdout/stderr, and
exit-zero wrappers. Preserve the localized V2 diagnosis for previously
saved incompatible paths during the actual host/WSL lifecycle.
- Run both validation probes asynchronously with a 5-second subprocess
timeout and 64 KiB output limit, leaving the shared backend responsive
while a CLI is slow.
- Treat saved versions as display metadata only: explicit add/browse
always validates the path again.
- Match the compatibility error code precisely, including its JSON HTTP
envelope, so unrelated missing-file/configuration errors are not hidden
by a matching filename.
- Reuse the existing translated message in all ten locales. No daemon
ownership, V1 fallback, package update, or native-shell-selection
change.

## Follow-up verification of the original PR

The original head `226e2d7b` already fixed the exact reported failure
with a real V1 binary. Independent rechecking found and corrected
adjacent gaps in this same PR:

| Check | Original PR | Completed PR |
| --- | --- | --- |
| Real OpenCode 1.18.25 rejected; real V2 accepted | PASS | PASS |
| Empty/unrelated successful help rejected | FAIL | PASS |
| Legacy help with exit zero localized at launch | FAIL | PASS |
| Other backend work proceeds during slow probes | FAIL | PASS |
| Explicit add rechecks a persisted V1 version | FAIL | PASS |
| Unrelated diagnostic mentioning `opencode_v2_required` retained | FAIL
| PASS |

The new regression tests were run against the old production code first:
three assertions failed (false capability acceptance, exit-zero help,
unrelated-error masking), then passed after the fix. A separate
source-extraction check executes the unchanged published probe and
component validation body: two 250 ms subprocess delays block the old
probe for about 638 ms, versus a Promise returned in about 5 ms after
the fix; a cached V1 version previously produced zero validation calls
and now produces one and rejects the path.

## Validation of the compatibility fix (`903d9159`)

- Full server suite on Windows: **391 passed, 2 skipped**.
- Electron native suite: **189 passed**.
- Focused compatibility/lifecycle/updater/HTTP/UI diagnostic suite: **79
passed** on Windows.
- Server, UI and Electron typechecks passed; server and UI production
builds passed.
- `git diff --check` and workflow YAML validation passed.
- Real CLI checks: V1 **1.18.25** refused with `opencode_v2_required`;
V2 beta builds **19151/19192** accepted; authenticated discovery of the
existing shared daemon succeeds. No service stop/restart or settings
mutation was performed.
- Actual subprocess fixtures exercise spaced/apostrophe/Unicode paths,
stdout/stderr and exit codes. HTTP integration proves that validation
neither mutates preferences nor blocks another request.
- Existing regressions retain stopped/running daemon discovery, startup
environment isolation, password-error redaction, deadlines, WSL command
forwarding, authenticated health, shared-service ownership and updater
behavior.
- Independent focused CI matrix passed on **Linux and macOS 26 ARM64**
(77 passed, 2 Windows-only skips each) and **Windows** (79 passed), in
run `34036886140`.

## Update with current `dev` / conflict resolution

Updated this branch with `dev` at `81aa4d24`, which now includes **#671,
#674 and #677**. The only textual conflict was in
`.github/workflows/pr-build.yml`, where #672 and #677 added CI jobs at
the same location. Both the OpenCode compatibility matrix and the macOS
ARM64 Tauri tests are retained, with both required by the package-build
gate. Parsed workflow comparisons verify that every non-build job is
identical to its originating parent and no build dependency was dropped.

The previously blocking Linux automation-registry fix **#671 is now
included through `dev`**, rather than duplicated. The full CI matrix is
rerunning on this combined state; require that result before merge.

Local checks after resolving the conflict: **391 server tests passed, 2
skipped; 192 Electron tests passed; server/UI/Electron typechecks
passed; workflow parent-preservation assertions and `git diff --check`
passed**. The conflict resolution itself changes no application code.

Automated CLI/HTTP tests are not an interactive Electron/macOS ARM64
smoke test on the reporter's machine, and cannot establish the absolute
absence of every possible side effect.

Maintenance: files already touched by the original PR remain oversized:
`packages/server/src/api-types.ts` (536 lines) and
`packages/ui/src/App.tsx` (855 lines). This follow-up does not grow
those files.
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.

2 participants