Windows-native + WSL + Linux compatibility, verified by executed checks#17
Windows-native + WSL + Linux compatibility, verified by executed checks#17RadioactiveCheese wants to merge 15 commits into
Conversation
The /api/open-folder endpoint was hardcoded for macOS: every other
platform got HTTP 501, which the frontend surfaces as a button that
silently does nothing — on the very platforms the README points at
("Windows via WSL").
Replace the darwin-only branch with folder_opener_command(), which
picks the platform's opener:
- macOS: open (unchanged)
- native Windows: explorer.exe
- WSL (detected via WSL_DISTRO_NAME / WSL_INTEROP / /proc/version):
convert the path with wslpath -w and hand it to explorer.exe, so
the folder opens in Windows Explorer via \wsl.localhost
- other Linux: xdg-open when present
501 is still returned when no opener exists for the platform.
Verified on Windows 11 + WSL2 Ubuntu: endpoint returns 204 and
Explorer opens the artifacts directory.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…xporter - ringer.py: dispatch manifest checks through Git Bash on win32 (RINGER_CHECK_SHELL override; clear 127 error when absent) instead of cmd.exe; taskkill /T for process-tree termination; non-destructive ctypes pid probe; os.startfile / xdg-open for the open-folder endpoint; skip doomed `ps` spawn on win32; platform-aware stdin display strings. - hooks/ringer_nudge.py: pid_is_alive probed with os.kill(pid, 0), which TERMINATES the target on Windows; now uses OpenProcess/GetExitCodeProcess. - dashboard: fileHref handles drive-letter paths (file:///C:/...), normalizes backslashes; Finder-specific copy neutralized. - templates/fix-swarm/checks/fix-swarm.py: export patches byte-faithfully (git diff captured as bytes; cp1252 text capture corrupted UTF-8 and injected CRLF on Windows). Verified by executed checks on native Windows: nested ringer run with a POSIX-syntax check passes, kill helpers terminate live children, probe leaves live processes running, node tests for fileHref, scratch-repo export/apply round-trip, and `ringer.py demo` 3/3 PASS (was 0/3). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ardcodes
- templates: replace /opt/homebrew/bin/python3.14 and bare python3 in check
commands with the {{PYTHON}} placeholder; cross-platform note in README.
- README: native Windows quickstart (python ringer.py, Git Bash requirement,
RINGER_CHECK_SHELL), Windows config path, engine caveats.
- config.sample.toml: Windows config location; macOS-only examples labeled.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Isolate USERPROFILE alongside HOME so Path.home() on Windows stays inside test temp dirs; absolute ringer.py path instead of a symlink requiring Developer Mode; close sqlite handles (Windows file locks); route /tmp hardcodes through tempfile.gettempdir(); inline the design-reference tokens that previously lived at an absolute path on the original dev machine; deterministic API error-path test; date assertion no longer pinned to the day it was written. Suite: 132 passed natively on Windows (pytest) and on WSL Ubuntu (unittest). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… lessons) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
# Conflicts: # ringer.py
OpenProcess succeeds for exited processes whose handles are still held (e.g. an unreaped child), which kept dead runs alive in active-runs reconciliation on Windows. Mirror the nudge hook: GetExitCodeProcess and treat only STILL_ACTIVE (259) as live. Reproduced before the fix (exited Popen child read True), verified after (False; live child unharmed). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…n win32
The validator's run_shell used shell=True (cmd.exe via COMSPEC), so a
POSIX-syntax {{BUILD_OR_TEST_COMMAND}} failed inside the validator even
though ringer.py now runs outer checks under Git Bash. Mirror ringer.py's
shell resolution (RINGER_CHECK_SHELL, PATH bash rejecting System32/WSL,
Git-for-Windows locations); rc 127 with a clear message when none exists.
Verified on Windows: a verify command using test/grep/{ ...; exit 1; }
passes through the validator, and a failing one still fails with output.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…shell
Seven kit validators (bakeoff, asset-swarm, test-hardening, focus-group,
repo-feature, doc-swarm, research-with-proof) ran build/render/proof
commands with shell=True — cmd.exe on native Windows — bypassing the Git
Bash contract that ringer.py's check runner now guarantees. Each script
gets the same _windows_posix_shell resolution and a run_user_command
helper preserving its original cwd/timeout/stderr semantics, with rc 127
and an actionable message when no POSIX shell exists. Verified by
importing all seven and executing test/{ ...; } commands through them
natively on Windows; POSIX branch unchanged; suite 132 green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…used Console processes commonly refuse taskkill without /F; the old fallback killed only the tracked parent with proc.terminate(), and since the parent then exited, the timeout path never escalated to kill_process_group — the worker's children survived. terminate_process_group now retries with taskkill /T /F before any parent-only fallback. Reproduced (grandchild survived) and verified fixed (parent + grandchild both die) on Windows. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Heads-up for review continuity: a fourth Codex finding landed on #16 just before it was closed (P1 — graceful |
…act model attribution
Four changes from Jon's UX review (2026-07-09), built as a 4-task Ringer swarm
(4/4 first-attempt PASS, executed checks) plus orchestrator review:
- Model attribution (the "gpt-5.6 isn't tracked" bug): eval rows and the HUD
state payload logged model="" for every codex task, and read-time registry
resolution mis-credited all of them to GPT-5.5. Now the effective model is
stamped at write time — task.model, else engine model_default, else parsed
from the actual composed command (effective_model_from_command). New
{model_args} placeholder makes the manifest "model" field work for codex
(expands to "-m <model>" only when a model is resolved). Registry gains
GPT-5.6 Sol/Luna/Terra (cited: OpenAI codex models page).
- scripts/backfill_model_from_logs.py: re-attributes historical empty-model
rows from "[ringer.py] command:" lines in raw worker logs. Evidence-only
(no guessing), dry-run, timestamped backup, atomic rewrite, idempotent.
- Work gating: the live status artifact renders "The work" for FINISHED tasks
only (placeholder until the first finish); no more "view the work log" on
running tasks. Final report unchanged.
- Ringside UX: "running now" pill buttons appear when 2+ runs are live
(state=live AND PID-alive in active-runs.json) — click to bounce between
runs; workers render as a 2-column expandable card grid (engine · model ·
elapsed · attempts · tokens, activity line only while running, full-row
expansion with live log stream); machine-strip and legend removed as
redundant. Historical artifact dropdowns untouched.
132 tests green (full suite minus the two pre-existing env-broken tests).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Ringside overhaul moved unfinished-task state out of worker rows and into the rounds strip's aria-labels; test_plain_english_artifact.py was migrated in that commit but the identical assertions in test_design_reference.py were missed (pre-existing failure on the overhaul branch, surfaced here because the portability work made this test file runnable off the original dev machine). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
This branch now also merges #18 (feat/ringside-overhaul, 9308df1) — merging or closing #18 separately is no longer necessary if this lands. The merge was clean except for one pre-existing issue in #18 itself: the Ringside work-gating change migrated the retry/working assertions in test_plain_english_artifact.py but missed the identical ones in test_design_reference.py (fails on 9308df1 standalone; it only ever passed on machines where that test file couldn't run). Fixed here in 383e7ba by mirroring the same migration. Combined branch verified: 147 tests green on native Windows (pytest) and WSL Ubuntu (unittest), plus the executed portability checks (nested POSIX-check run, full process-tree kills) pass on both. |
Fold in the bubblewrap counterpart to the macOS Seatbelt wrapper (engines/opencode-sandboxed-linux.sh, same contract: network + reads open, writes confined to taskdir + per-run scratch + OpenCode state dirs, --no-sandbox wired for the allow_full_access gate) and the wsl.exe -e bridge (engines/opencode-sandboxed-wsl.sh) that translates C:\ task dirs to /mnt paths, plus the confinement smoke test. Docs updated; wrappers no longer described as macOS-only. Verified by execution: bwrap smoke shows taskdir writable, HOME and /tmp read-only, network open; a real Windows-side ringer probe run drove opencode (GLM-5.2) through the bridge inside the sandbox — PASS attempt 1, 5s, 8k tokens, POSIX check green. .gitattributes pins *.sh to LF so autocrlf checkouts cannot hand WSL a CRLF script. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
9ef6e82 closes the last known gap from the PR body: the OpenCode sandbox is no longer macOS-only. New engines/opencode-sandboxed-linux.sh (bubblewrap, same confinement contract as the Seatbelt wrapper) and engines/opencode-sandboxed-wsl.sh (wsl.exe -e bridge translating C:\ task dirs to /mnt) — verified by executing the bwrap confinement smoke (taskdir writable, HOME and /tmp read-only, network open) and a real Windows-side ringer probe run through the full stack (ringer.py on Windows → WSL bridge → bwrap → opencode/GLM-5.2): PASS attempt 1, 5s, 8k tokens, POSIX check green. Also adds .gitattributes pinning *.sh to LF so autocrlf Windows checkouts can't hand WSL a CRLF script. Suite 147 green. |
…ox lane) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Thanks for the amount of work and testing that went into this. There are several useful changes here, especially the Windows shell and process fixes and the cross-platform sandbox work. The problem is scope. This PR now combines core Windows runtime behavior, validator execution, template portability, dashboard and open-folder behavior, Linux/WSL sandboxing, documentation, and pieces of other Ringside work. That is too much to review or roll back safely as one change. Please break this into focused PRs:
Keep the relevant tests and documentation with each change. Please also rebase against current I am going to hold off on merging this version. The work is useful; it needs to arrive in smaller pieces so each change has a clear verification and rollback boundary. Start with the core Windows runtime PR. |
|
First, plainly: this work is extremely valuable and we want it in Ringer. You are the only person who has done the real Windows work — actual multi-platform validation on real machines, and fixes that target, with precision, the only three genuinely non-portable chokepoints in this codebase: how checks get shelled (the Git Bash finder), how process trees are controlled (OpenProcess/ The reason we're closing this branch is composition, not quality: about half its 52 files are a stale copy of pre-#18/#26 main — Ringside, model-log, and eval changes that have since landed in different form — which is why it conflicts and why nobody can audit which lines are yours versus overtaken history. Your work deserves better than being buried in a diff that's half archaeology. So: please resubmit as small, separately auditable PRs on current main — we will review them fast, and your authorship stays on every commit:
And here's the part we're doing for you: none of us has a Windows machine, so we're adding a GitHub Actions workflow to main — macOS and Linux run the full suite as required checks, plus a Thank you for carrying this further than anyone else has. We'll be watching for the split PRs. |
macOS and Linux run the suite on every push/PR. The windows-latest job is continue-on-error until native-Windows portability PRs (invited in #17) turn it green, then it flips to required. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Supersedes #16 (same branch, same commits — reopened from the correct account/fork). The three Codex review findings from #16 are already addressed on this branch: e8cff49 (STILL_ACTIVE check in win32 pid_is_alive), 2db0795 (fix-swarm validator verify commands through Git Bash), 83272b2 (same POSIX-shell routing swept across all seven kit validators).
What
Makes Ringer run natively on Windows (and stay green on WSL, Linux, and macOS), fixing every macOS/POSIX-only assumption found by a 5-scout Ringer review swarm over the whole repo. Also merges
fix/open-folder-cross-platform, whosefolder_opener_command()(with WSLwslpath→ Explorer translation) supersedes the interim endpoint fix.Key fixes
asyncio.create_subprocess_shell→ COMSPEC), so every POSIX check died with'{' is not recognizedwhile workers succeeded. Checks now dispatch through Git Bash on win32 (auto-detected;RINGER_CHECK_SHELLoverride; the WSL launcher in System32 is rejected; loud rc-127 error instead of a silent cmd.exe fallback).os.kill(pid, 0)liveness probes inhooks/ringer_nudge.pyandringer.pyterminate the target on Windows (TerminateProcess); reading active runs could kill a live run. Replaced with non-destructiveOpenProcess/GetExitCodeProcessprobes (STILL_ACTIVE required).os.killpg(absent on Windows), orphaning worker process trees; nowtaskkill /T(/Fon kill) with graceful fallback.git diffin text mode: cp1252 decode corrupted UTF-8 and injected CRLF on Windows. Now byte-faithful.openonly →folder_opener_command()for macOS/Windows/Linux/WSL (from the merged branch).fileHrefproduced brokenfile://C:%5C...URLs for drive-letter paths; Finder-specific copy neutralized./opt/homebrew/bin/python3.14; all check commands now use a{{PYTHON}}placeholder.USERPROFILEisolation (so tests can't touch the real home dir on Windows), sqlite handles closed,/tmpand symlink and Mac-only-path assumptions removed, plus one date time-bomb defused.python ringer.py, Git Bash requirement,RINGER_CHECK_SHELL); known limitations documented (child-count telemetry on Windows, macOS-only Seatbelt wrapper).Verification (all executed)
ringer.py demo(3 real codex workers)All fixes were produced by Ringer fix swarms in isolated worktrees with executed verify scripts as checks; MODEL-NOTES carries the run evidence and process lessons.
Known out of scope: the parked
hud/Tauri prototype has two documented P2 findings (bash-onlybeforeBuildCommand,$HOME-scoped asset protocol) left unchanged — not verifiable here without a Tauri build.🤖 Generated with Claude Code