Skip to content

Tighten file_lock pin scope: 'reading OR mutating' shared files (PR #641 R2-B4 follow-up) #649

Description

@michael-wojcik

Background

PR #641 Round-2 R2-B4 finding identified a scope-mismatch in the project CLAUDE.md pinned rule for file_lock:

"Any code doing read-mutate-write on shared files (CLAUDE.md, journal files, ring buffer logs) MUST use this helper..."

The R2-B4 finding (now fixed in baeb2d8 via the comment edit on session_init.py:389) demonstrated that read-only access to shared files can suffer torn reads if a concurrent writer is mid-write. The session_init.py:389 case: a read of prev_session_dir could observe a torn write from a concurrent session_init invocation racing the WRITE step at L1148.

The current pin says READ-MUTATE-WRITE, implying read-only access is fine. But the R2-B4 finding empirically shows otherwise: even pure reads of shared files need lock-acquisition for consistency.

Symptom

Without lock-acquisition on reads:

# concurrent session A writes:
with file_lock(path):
    new_content = compute(read(path))
    atomic_write(path, new_content)

# concurrent session B reads (NO LOCK):
content = read(path)  # may observe torn state mid-A-write

Atomic-rename writes mitigate this for the file-content level (POSIX atomic-rename guarantees), but the multi-step orchestration around the rename (e.g., _compute_substituted_directive reading prev state to derive new state) is NOT atomic and CAN observe inconsistent intermediate state.

Proposal

Tighten the project CLAUDE.md pin from:

"Any code doing read-mutate-write on shared files MUST use this helper..."

to:

"Any code reading OR mutating shared files concurrently with other PACT writers MUST use this helper. Read-only access still requires lock-acquisition to defend against torn reads from concurrent writers."

Affected sites to audit

After tightening the pin, audit existing code for read-only access to shared files that may need lock retrofit:

  • claude_md_manager.py — read paths on CLAUDE.md
  • session_journal.pyread_events, read_last (already locks per pin's current scope, but verify)
  • session_init.py — read paths on session_dir contents
  • pact_context.py — context-file reads
  • staleness.py — pinned-context staleness checks (already locks, verify)
  • failure_log.pyread_failures (already locks per pin's current scope)

Acceptance criteria

  • Project CLAUDE.md file_lock pin updated to "reading OR mutating" scope.
  • Read-path audit completed across the 6 sites above; any unlocked reads either documented as safe (e.g., one-shot read at session start before concurrent writers exist) or retrofitted with file_lock.
  • Test or assertion proving torn-read defense is in place where lock retrofit is applied.

Cross-references

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions