This repository was archived by the owner on Aug 25, 2026. It is now read-only.
fix: manage Codex session locks across lifecycle hooks - #82
Merged
Merged
Conversation
Track Codex locks by stable thread identity so isolated tool calls preserve ownership and matching SessionEnd hooks release only their own home's lock. Preserve Grok precedence, legacy numeric owners, and JT's existing PreToolUse hook.
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 subscribe to this conversation on GitHub.
Already have an account?
Sign in.
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.
Intent
Port only the Codex session-lock lifecycle contract from upstream kunchenguid#1109 into JTInventory/firstmate. Add bounded SessionStart and SessionEnd lock hooks while preserving JT's existing PreToolUse hook; support structured Codex thread owners, same-thread preservation across PID isolation, different-thread exclusion, matching home-local release, legacy numeric locks, and ambient CODEX_THREAD_ID detection with mandatory GROK_AGENT=1 precedence. Preserve JT's Herdr and multi-home contracts. Include focused deterministic coverage for Grok-primary protection, independent homes, numeric legacy locks, and exact non-symlink SessionEnd release. Keep the real Codex /quit test opt-in only; it timed out on this host and is explicitly non-blocking by captain recovery. Do not include GitHub/bootstrap diagnostics, daemon changes, path restructuring, pane restarts, or any unrelated upstream slice.
What Changed
SessionStartandSessionEndhooks to claim home-local locks and release only exact matching thread owners, while preserving the existingPreToolUseguard./quittest remaining opt-in; the focused pipeline checks passed.Risk Assessment
✅ Low: Captain, the remediation resolves all three prior findings without widening the narrowly scoped lifecycle port, and no new material risk was found.
Testing
The successful full baseline, focused lock and session-start suites, Herdr regression suite, and direct registered-hook transcript demonstrate the requested lifecycle end to end; the real Codex
/quittest remains intentionally opt-in, and the broader external Herdr lab was not allowed past its gate safety guard.Evidence: End-to-end Codex session-lock lifecycle transcript
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
🔧 **Review** - 3 issues found → auto-fixed ✅
bin/fm-lock.sh:79- Intent requires support for “legacy numeric locks,” but a live pre-upgrade lock containing<pid>is no longer recognized as the same Codex session whose new owner is<pid>|codex:<thread>|harness. The changed comparison falls through to live-owner refusal. Confirm that numeric locks must retain same-session reacquisition, then compare the numeric owner with the structured owner’s PID under the acquisition lock.bin/fm-codex-session-lock-hook.sh:26- The lifecycle hook silently exits whenjqis unavailable, and the registered wrapper does the same.jqis not a base dependency for normal tmux installations, so on a supported clean install neither SessionStart nor SessionEnd works and/quitleaves the lock behind. Parse with an existing required dependency or otherwise remove the optional-jqfailure path.bin/fm-session-lock-lib.sh:43- Lock ownership gives inheritedCODEX_THREAD_IDprecedence over Claude and Pi markers, whilefm-harness.shcorrectly gives those harnesses precedence. A Claude or Pi secondmate launched from Codex can therefore be recorded with the parent’s Codex thread and treated as the same owner. Mirror the verified harness-marker precedence here or clear the inherited marker from non-Codex launches.🔧 Fix: Fix Codex session-lock lifecycle compatibility
✅ Re-checked - no issues remain.
✅ **Test** - passed
✅ No issues found.
bash bin/fm-run-behavior-tests.shPre-supplied successful baseline:bash bin/fm-run-behavior-tests.shbash tests/fm-codex-session-lock.test.shbash tests/fm-session-start.test.shbash tests/fm-codex-session-lock-live-e2e.test.sh— confirmed the real/quitcheck remains opt-inbash tests/fm-backend-herdr.test.shInvoked the exact registeredSessionStartandSessionEndhook commands with lifecycle JSON payloadsExercised same-thread PID-isolated reacquisition, different-thread exclusion, independent homes, exact release, numeric legacy retention, symlink refusal, Grok precedence, and preservedPreToolUsebash tests/fm-backend-herdr-presentation-e2e.test.sh— provisioning was blocked by the expectedNO_MISTAKES_GATEsafety marker and was not bypassed because it would drive an external Herdr/Treehouse lab✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.