Skip to content

Preserve unsafe journal leaves during recovery writes #1151

Description

@bcdonadio

Observed behavior: Reconciliation can replace a journal that becomes unsafe after the locked read and before an inner recovery write. At before-source-patterns-merge, create a hard link to the current journal or change its mode from 0600 to 0644, then throw a generic observer error. The inner blocked-state recording writes a new 0600 inode over the journal pathname without authenticating the existing leaf. The pathname's original bytes and inode are lost in the mode case; an external hard link retains the original inode in the link case, but the journal pathname no longer exposes that evidence.

Expected behavior: Authenticate the current journal leaf and its admitted identity before replacing it during recovery; refuse unsafe/changed leaves without overwriting their inode or bytes. Preserve the primary failure and recording failure together, retaining the journal-parent authority and one-attempt contract. Initial absent journal publication must remain safe.

Root cause: throwAfterBlockedRecording sets recording attempted and invokes writeJournal; the latter uses parent-authenticated atomicWritePrivateFile but does not authenticate its destination leaf before rename. The outer authenticated reread is then skipped because recording was attempted.

How to reproduce: Use the hermetic linked-worktree reconciliation fixture with a legacy source pattern. After its planned journal is published, at before-source-patterns-merge save the journal inode/bytes, create a fixture hard link or chmod only that fixture to 0644, and throw a generic error. Calling public reconcileWorktrees replaces the journal with phase=blocked. Assert the pathname's original inode/bytes/mode/link count: both variants fail. The source owner ran the two public-seam reproductions against candidate 3971ac0 and baseline 7c19172; both fail identically. The candidate worktree remained unchanged.

Severity: P2. This is inherited late-write behavior and incomplete leaf hardening, requiring same-owner journal-directory mutation during an attempt. It does not parse unsafe bytes, publish a malicious map, or overwrite the external hard-link alias. The unsafe-mode case does discard the original journal inode from the namespace.

Origin: Follow-up to #1109 and #1107, PR #1149. External review thread on PR #1149 ("Authenticate the journal before the first recovery write") and candidate round-three review/independent Daybreak validation. Outside the frozen S5 campaign scope; preserve as independently actionable follow-up. The original fix authenticates journal readers; this report concerns the later recovery writer, not a duplicate of reader admission.

Environment:

  • Agent: Codex Daybreak Blue high validation, Astra owner
  • Connector: CLI/public reconciliation seam
  • OS: Fedora Linux; Node 25.9.0; Vitest 4.1.10

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

    Fields

    Priority

    Medium

    Effort

    None yet

    Projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions