Conversation
Every session start on Cygwin (Git for Windows) refused the fleet lock and dropped to read-only with "cannot locate harness process in ancestry", so spawning, steering, merging, the wake-queue drain, and supervision repair were skipped on every start. Two independent causes, both on the identity path. Cygwin's ps has no -o option at all and fails the whole invocation with "unknown option -- o", so the ancestry walk aborted on its first hop. The walk now reads comm, args, and ppid through accessors that fall back to Cygwin's fixed ps columns, leaving the procps/BSD path unchanged. That alone does not resolve the session: the parent link from a shell the harness spawns does not cross the Cygwin boundary, and Cygwin reports that shell's PPID as 1, so no walk can reach a harness that is a native Windows process. Identity is instead taken from the session pid the harness publishes and confirmed against the Windows process table before it is used - the pid must still be live and its executable must independently identify a verified harness - so an absent, stale, or non-harness value is discarded rather than bound. Walking the real Windows parent chain was implemented and then removed as unsafe. MSYS emulates exec by spawning a fresh Windows process and exiting the old one, so intermediate shells vanish and a child's recorded parent is routinely a pid that no longer exists; Windows never reparents an orphan, so that dangling id stays and can be reissued to an unrelated process. Following it can bind a home's lock to the wrong process, which is the failure this file exists to prevent. A harness that publishes nothing stays unresolved, which leaves the session read-only exactly as before. Windows pids are tagged rather than stored bare. They are a different namespace: kill -0 reports a live Windows process as dead, and the number can collide with an unrelated live Cygwin pid. The tag makes the value non-numeric, so a consumer that treats it as a local pid - including a future kill - refuses it instead of acting on the wrong process. fm-sessionstart-nudge.sh carried a private second copy of the ownership walk and so stayed wrong after the owner was fixed, nudging a session that already held the lock. It now asks the owning function. Verified on Windows 11 (Git Bash, Cygwin ps 3.4.10): the lock is acquired, reports its holder, is idempotent, and refuses a bogus, dead, or non-harness published pid. Regressions cover both platform departures behind a fake process table, so they run on Linux and macOS CI too. The pre-existing e2e failure in this suite on Windows is unchanged from main; it cannot exec its symlinked fixture. Refs kunchenguid#3396 Claude-Session: https://claude.ai/code/session_01F9T29YDqYSkQeDTC2Nfi7h (cherry picked from commit 8b281b7)
Delegating the nudge to fm_session_lock_owned_by_self changed the question it asks. The nudge asks whether a process in this ancestry took the lock; the ownership predicate additionally requires a verified harness in that ancestry, so a session whose lock was written by a plain shell started being nudged to run session start again. tests/fm-sessionstart-nudge.test.sh pins the looser contract deliberately. The walk stays local, now reading ppid through the portable accessor so it also survives a ps with no -o option, and defers to the ownership predicate only for a Windows-tagged holder, which is not in this process table at all. (cherry picked from commit 0baf64f)
…the lock The Windows identity added in this branch introduced a second shape into state/.lock. Six gates read that field, and each one answered "is this value usable" with its own inline numeric test, so every one of them read a valid Windows holder as malformed. The visible cost was concentrated in startup completion: the record was never written, and the clear/compact check that consumes it could never match, so every clear or compact on Windows repeated the full startup sequence. The deferred network sweeps reported ownership as changed when it had not, and the Stop auto-arm treated a dead Windows session as an unreadable lock rather than a recoverable one. fm-lease.sh was the outlier: rather than refusing a value it could not use, `tr -cd '0-9'` reduced the tag to its digits and produced a number naming an unrelated process in the local table. It happened to fail closed downstream, but deriving a wrong-namespace pid is precisely what the tag exists to prevent, so it now takes the value whole and requires a local pid. fm_session_pid_valid is now the single owner of that question and every gate delegates to it, so a third identity shape cannot split them again. Verified against the shipped bytes of each gate with a tagged lock: startup completion now records and is recognized (main's gate reruns the full startup on the same input), both network-ownership gates authorize their sweeps, and a tagged lock yields no lease holder pid instead of 7204. (cherry picked from commit 9256182)
…concurrent acknowledgements
… blocked by CreateFileMapping Win32-5
…y lock acquisition
…ish lifetime markers
…s/fm-public-followup.test.sh. The fixture now stops and joins its scoped remote-worker tree before deleting temporary files, and reports failure if shutdown cannot be confirmed. This prevents the late writer that caused `Directory not empty`; `git diff --check` passes. Focused Bash execution was unavailable because managed Git Bash fails with Win32 error 5; host verification command: `FM_TEST_ONLY=test_remote_secondmate_loop_delivers_and_retires bash tests/fm-public-followup.test.sh`. Windows Claude ownership has not been verified. That run-scoped exception was not applied to this CI failure
|
Speaking as Kun's firstmate: triage for #4803 ( Classification: opt-in (tip vs main VISION (per-rule, inspected tip vs main + unconfigured path):
Attestation: MATCH ( |
|
Now marked ready for review. The draft status noted in the earlier triage is no longer current. |
|
@kunchenguid, could you please review this PR when you have a chance? Thank you. |
|
@kunchenguid, to make review easier I'm splitting this PR into smaller pieces. |
Scope and verification limits
Windows Claude ownership has not been verified.
Proceeding with this draft update under the explicitly accepted evidence exception does not certify Windows Claude support.
The implementation remains an explicit-opt-in native Windows Codex experiment restricted to temporary, empty-fleet homes, not general Windows fleet or Linux launcher support.
Natural-language Detection interpretation has not been live-model tested; the previously reported tagged foreign-owner concern remains unreproduced and is not claimed fixed.
Authorship and history
This continues #3553 with Lloyd's original commits and attribution preserved:
aa434629,a975ea4c, and36dbddc3.Original author approval: #3553 (comment).
The upstream integration is a normal merge of
203a69a3007ea5d06f70869f39277cdbde430903and65a3bac6031286b4058360859a9522a50a09bb14, preserving both histories without a rebase.Current validation evidence
Published head:
ee9be1c8386eb4833ee630dc748782575c3babfc.All 19 GitHub checks passed on this head, and GitHub reports no merge conflicts. The PR remains draft and unmerged.
The final test-only CI repair uses the existing scoped remote-worker stop-and-join helper before fixture directory deletion, addressing the cleanup failure in the public-followup suite.
The canonical local verification described next was at the documentation head
755daafd3b9ceb648a12c3d712984d8414862d9e; final-head GitHub lint and behavior checks passed separately.Full canonical ShellCheck/actionlint, documentation audience/link checks, and targeted ownership/reference/portable-host suites passed at that documentation head.
The Linux portable-host run passed 54 checks, with three Windows-only skips.
Real Windows Codex launcher/model, native lifecycle and receipt verification passed at
12b206150162fd47dcb9d30ffeaf36f98f7461bc; the later change to the published head contains only comments and documentation, including the explicit Claude limitation.Those Windows runs had zero skips and clean tracked diffs, including all 57 tool checks and 39 receipt assertions.
The generated report below distinguishes automated fixture/ancestry evidence from live-model evidence; an “untested” live label does not mean the separately recorded automated check failed.
Earlier findings saying no exception applied predate the subsequent explicit acceptance recorded above; they remain below as historical run evidence, not a claim that Claude was verified.
The generated lint warning records a managed Windows shell invocation failure; the separately executed exact-head canonical full lint passed without relaxing checks.
What Changed
Risk Assessment
✅ Low: The change is strongly bounded to an explicit-opt-in, temporary-home, empty-fleet experiment, and the reviewed source preserves both parents’ ownership and recovery invariants without a substantiated new defect.
Testing
The host driver exercised the real Windows Codex launcher/model and native ownership surfaces at exact head
12b2061; all three live scenarios passed. The portable fake-server fixture, staged integration checks, and local graph checks are retained as non-live supporting observations and therefore do not establish scenario passes under the live-validation contract. Windows Claude ownership, natural-language Detection interpretation, and the tagged foreign-owner path remain untested.tests/fm-native-owner-launcher-live-e2e.test.shtranscript: exit 0, no capability skip, two model-observed acknowledgement cycles, interruption recovery, restart, and clean…tests/fm-native-owner-receipt-live-e2e.test.shtranscript: exit 0, no capability skip, 39 receipt assertions, exclusive acquisition, restart recovery, and ambiguous-owner re…Evidence: Exact-head real Windows Codex launcher/model run
Evidence: Exact-head Windows native ownership and receipt run
Evidence: Portable host-loop and capability-isolation evidence
Evidence: History-preserving integration proof
Evidence: Integrated Linux verification record
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
⏭️ **Rebase** - skipped
Step was skipped.
✅ **Review** - passed
✅ No issues found.
🔧 **Test** - 2 issues found → no changes applied ✅
powershell.exe -NoProfile -NonInteractive -File .\bin\fm-native-codex.ps1 -BuildOnlyPublic launcher invocation without-ExperimentalCompiledfm-native-owner.exe launch --experimental <populated-temporary-home>with sentinel and owner-record checksCompiledfm-native-owner.exe launch --experimental <non-temporary-path>with no-creation checknode tests/fixtures/native-owner/tool-gate.test.mjsnode tests/fixtures/native-owner/host-lifecycle.test.mjsnode tests/fixtures/native-owner/app-server-policy.test.mjsnode tests/fixtures/native-owner/host-evidence.test.mjs(subprocess cases setup-blocked byspawn EPERM)Isolated realcodex app-server --stdioJSONL drive throughinitialize,config/read,thread/start,app/installed, andmcpServerStatus/listAttemptedbin/fm-test-run.sh tests/fm-native-owner-app-server-policy-live-e2e.test.sh(Git Bash blocked before execution)Docker image enumeration, Git Bash, Node subprocess, and WSL capability probesgit merge-base --is-ancestorfor 203a69a, 65a3bac, and 09d19aa plus exact merge-parent verificationFinal clean-worktree and transient-artifact check🔧 No changes applied.
✅ Re-checked - no issues remain.
tests/fm-native-owner-launcher-live-e2e.test.shtranscript: exit 0, no capability skip, two model-observed acknowledgement cycles, interruption recovery, restart, and clean…tests/fm-native-owner-receipt-live-e2e.test.shtranscript: exit 0, no capability skip, 39 receipt assertions, exclusive acquisition, restart recovery, and ambiguous-owner re…git status --short --branchandgit rev-parse HEADgit show --no-patch --pretty=fuller 12b206150162fd47dcb9d30ffeaf36f98f7461bcandgit rev-list --parents -n 1 12b206150162fd47dcb9d30ffeaf36f98f7461bcgit merge-base --is-ancestorfor203a69a,65a3bac, and09d19aaagainst12b2061Reviewed host-produced exact-headbash bin/fm-test-run.sh tests/fm-native-owner-launcher-live-e2e.test.shevidenceReviewed host-produced exact-headbash bin/fm-test-run.sh tests/fm-native-owner-tool-gate.test.sh tests/fm-native-owner-receipt-live-e2e.test.shevidenceReviewed staged integrated-treetests/fm-session-lock-ancestry.test.shand five adjacent-suite transcriptsReviewed the supplied canonical lint completion and exit records without rerunning lintComputed SHA-256 hashes for all ten supplied host evidence files and attempted to copy them into the dedicated evidence directoryFinalgit status --shortandgit rev-parse HEADcleanliness/head check✅ **Document** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.