Skip to content
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
JTInventory merged 4 commits into
mainfrom
fm/firstmate-port-1109-codex-lock-0727
Jul 27, 2026
Merged

JTInventory merged 4 commits into
mainfrom
fm/firstmate-port-1109-codex-lock-0727

Conversation

@JTInventory

Copy link
Copy Markdown
Owner

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

  • Register bounded Codex SessionStart and SessionEnd hooks to claim home-local locks and release only exact matching thread owners, while preserving the existing PreToolUse guard.
  • Support structured Codex owners, same-thread reuse across PID isolation, different-thread exclusion, legacy numeric locks, independent homes, and Grok precedence over inherited Codex markers.
  • Document the lifecycle contract and add deterministic coverage, with the real Codex /quit test 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 /quit test 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
Codex session-lock lifecycle evidence

1. Registered SessionStart creates a structured owner in home A
home A lock: 3496138|codex:thread-alpha|harness
result: structured thread owner recorded

2. A PID-isolated call from the same thread preserves that exact owner
before: 3496138|codex:thread-alpha|harness
after:  3496138|codex:thread-alpha|harness
result: exact owner preserved

3. A different Codex thread is excluded
exit: 1
error: another live firstmate session holds the lock (owner 3496138|codex:thread-alpha|harness); operate read-only until resolved
lock remains: 3496138|codex:thread-alpha|harness

4. The same thread can own independent homes; releasing A does not touch B
home B before release: 3496138|codex:thread-alpha|harness
home A after matching SessionEnd: free
home B after A release: 3496138|codex:thread-alpha|harness

5. Mismatched SessionEnd leaves B owned; exact matching SessionEnd releases it
home B after mismatched end: 3496138|codex:thread-alpha|harness
home B after exact end: free

6. Legacy numeric and symlink locks are never removed by SessionEnd
legacy numeric lock after end: 424242
symlink lock still present: yes
symlink target still contains: 999|codex:thread-alpha|fallback

7. GROK_AGENT=1 takes precedence over an ambient Codex thread marker
detected harness: grok

8. Hook registration keeps JT's Bash PreToolUse contract
PreToolUse matcher: Bash
PreToolUse command: fm-cd-pretool-check.sh (preserved)

OVERALL: lifecycle behavior matches the requested Codex lock contract

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 when jq is unavailable, and the registered wrapper does the same. jq is not a base dependency for normal tmux installations, so on a supported clean install neither SessionStart nor SessionEnd works and /quit leaves the lock behind. Parse with an existing required dependency or otherwise remove the optional-jq failure path.
  • ⚠️ bin/fm-session-lock-lib.sh:43 - Lock ownership gives inherited CODEX_THREAD_ID precedence over Claude and Pi markers, while fm-harness.sh correctly 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.sh
  • Pre-supplied successful baseline: bash bin/fm-run-behavior-tests.sh
  • bash tests/fm-codex-session-lock.test.sh
  • bash tests/fm-session-start.test.sh
  • bash tests/fm-codex-session-lock-live-e2e.test.sh — confirmed the real /quit check remains opt-in
  • bash tests/fm-backend-herdr.test.sh
  • Invoked the exact registered SessionStart and SessionEnd hook commands with lifecycle JSON payloads
  • Exercised same-thread PID-isolated reacquisition, different-thread exclusion, independent homes, exact release, numeric legacy retention, symlink refusal, Grok precedence, and preserved PreToolUse
  • bash tests/fm-backend-herdr-presentation-e2e.test.sh — provisioning was blocked by the expected NO_MISTAKES_GATE safety 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.

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.
@JTInventory
JTInventory merged commit bd3060f into main Jul 27, 2026
6 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant