Skip to content

Crash Recovery Journals

tonythethompson edited this page Jul 10, 2026 · 1 revision

Crash Recovery Journals

Crash Recovery Journals are a set of durable, JSON-based state files used by Numan to ensure transactional integrity across operations that span multiple filesystem locations. Because Numan cannot atomically commit changes to both its internal state (like the lockfile) and external Nushell locations (like the plugin.msgpackz or numan.nu autoload file), it uses these journals to make interrupted work detectable and safely recoverable.

The system employs three primary journals: the Plugin Activation Journal, the Module Autoload Journal, and the Lifecycle Journal. These journals allow the numan activate command or the numan doctor utility to reconcile the system's state if a process is killed, the filesystem fails, or the environment drifts between operations.

Core Journaling Architecture

The journaling system follows a "Prepared-then-Replaced" protocol. Before any mutation to an external Nu-owned file occurs, Numan writes a journal at the Prepared stage. Once the external mutation is successful, the journal is updated to Replaced before internal Numan state (the lockfile) is updated.

General Transaction Protocol

The following diagram illustrates the standard flow for a journaled transaction, specifically for module autoloading.

flowchart TD
    Start[Start Mutation] --> Lock[Acquire Mutation Lock]
    Lock --> Snapshot[Create State Snapshot]
    Snapshot --> PrepJournal[Write Prepared Journal]
    PrepJournal --> External[Mutate External File]
    External --> ReplaceJournal[Update Journal to Replaced]
    ReplaceJournal --> Internal[Update Internal Lockfile]
    Internal --> Clean[Delete Journal]
    Clean --> Unlock[Release Mutation Lock]
Loading

The flow ensures that if the process fails at "Mutate External File", the journal remains in the Prepared state to signal an abort or retry.

Plugin Activation Journal

Stored at $NUMAN_ROOT/state/pending-activation.json, this journal tracks the registration of Nushell plugins. It specifically records the Nu identity (executable hash and version) to ensure that recovery is only attempted in a matching environment.

Data Structures

Field Type Description
nu_executable_sha256 String SHA-256 of the Nu binary used for registration.
nu_version String The version of Nushell detected.
plugin_registry_path String Path to Nu's plugin registry (e.g., plugins.msgpackz).
entries Vec<Entry> List of plugins being registered and their status.

Each entry in the journal tracks a status:

  • Prepared: The intent to register is recorded.
  • Registered: The plugin add command succeeded, but the lockfile is not yet updated.
  • Failed: The registration failed, typically including an error message.

Module Autoload Journal

Stored at $NUMAN_ROOT/state/pending-autoload.json, this journal manages the generation and replacement of the numan.nu vendor autoload file. It is critical because module activation changes the future startup behavior of Nushell.

Recovery Logic

The PendingAutoload structure provides specific recovery methods based on the transaction stage:

  • recover_prepared(): Verifies if the live managed file still matches the recorded previous state. If it does, the journal is cleared (safely abandoned).
  • recover_replaced(): Verifies that the managed file matches the candidate_sha256. If successful, it allows the lockfile and autoload-state.json to be updated to match the external reality.
flowchart TD
    Check[Inspect Journal] --> Stage{Stage?}
    Stage -- Prepared --> VerPrev{Matches Previous?}
    VerPrev -- Yes --> Abandon[Clear Journal/Safe]
    VerPrev -- No --> Drift[Block/Drift Detected]
    Stage -- Replaced --> VerCand{Matches Candidate?}
    VerCand -- Yes --> Complete[Finish Lockfile Update]
    VerCand -- No --> Drift
Loading

Lifecycle Journal

The Lifecycle Journal (pending-lifecycle.json) manages high-level package operations such as updates, removals, and nupm imports.

Lifecycle Operations and Stages

Operation (LifecycleOp) Stages (LifecycleStage) Description
Update Prepared, PayloadsStaged, PayloadsPromoted, SelectionCommitted Replaces a package with a newer version.
Remove Prepared, SelectionCommitted Removes a package from the lockfile and deletes payloads.
NupmImport Prepared, PayloadsStaged, PayloadsPromoted, SelectionCommitted Imports a local package from nupm into Numan.

Drift and Identity Validation

A key feature of Numan journals is the validation of the Nu identity. If the Nushell binary is updated (changing its hash or version), Numan considers the journal "stale."

Identity Matching Logic

pub fn matches_nu_identity(&self, nu_executable_sha256: &str, nu_version: &str) -> bool {
    self.nu_executable_sha256 == nu_executable_sha256 && self.nu_version == nu_version
}

In numan activate, the system performs a preflight check. If a stale journal is detected, it bails and directs the user to run numan init --refresh to reconcile the environment before attempting recovery.

Conclusion

Crash Recovery Journals provide the "transactional glue" for Numan's inert install model. By separating intent (Prepared) from execution (Replaced/Registered), Numan ensures that its authoritative lockfile remains synchronized with external Nushell integration points, even in the event of unexpected process termination. The numan doctor utility further leverages these journals to provide automated state repair.

Clone this wiki locally