ADR-0005: Concurrency-Hardened Storage and Automated Schema Migration
Status
Accepted
Amended by ADR-0034: abandoned temporary files left by a killed writer are reclaimed under a bounded policy.
Context
As PALEE vaults grow in complexity, notes may be created outside the CLI (by Obsidian plugins, manual text editing, or external sync engines) without the canonical palee_schema: 1 version attribute. Simultaneously, multi-process CLI operations, background automated tasks, and async command pipelines create high-frequency write contention where intra-process temporary file collisions and unhandled exception traces could degrade reliability.
Decision
We implemented a multi-layered storage hardening and schema migration strategy:
Entropy-Augmented Collision-Proof Temporary Files:
- In
atomicWrite(), temporary filenames are constructed using${targetPath}.tmp.${process.pid}.${crypto.randomBytes(4).toString('hex')}. - Eliminates intra-process race conditions where concurrent promises in the same process instance write to overlapping temporary filenames.
- Unlinks the temporary file in the outer
catchonce a write, fsync, or rename failure is not retried or its retries are exhausted (WindowsEPERM/EBUSYis retried first); the file descriptor itself is closed in an innerfinally. A process killed by a signal reaches neither path and leaves the file behind; ADR-0034 records how that residue is reclaimed, bounded to the target it belongs to.
- In
Automated OCC Schema Migration (
palee migrate --fix):- Extends the
migrateCLI command with an automatic--fixflag. - Discovers notes containing a valid
palee_idbut missingpalee_schema. - Computes the pre-write SHA-256 fingerprint and applies
atomicWrite()with optimistic concurrency control (expectedFingerprint) to upgrade frontmatter topalee_schema: 1safely. - Tracks failed file paths in the validation report to guarantee atomic convergence.
- Extends the
CST (Concrete Syntax Tree) YAML Document Frontmatter Serializer:
- Replaced ad-hoc JSON array serialization with unified
yamlpackageDocumentCST formatting. - Ensures newly generated frontmatter arrays (
depends_on,tags) serialize as standard YAML block sequences (- item) instead of bracketed strings.
- Replaced ad-hoc JSON array serialization with unified
Timezone-Safe Local Calendar SM-2 Arithmetic:
- Decomposes
YYYY-MM-DDstrings into year, month, and day components and uses local date arithmetic with adue.setFullYear(year)guard to eliminate 1900-offset bugs for years0000–0099and negative-UTC-offset day shifts.
- Decomposes
Consequences
- Positive:
- Vault notes without schema versions can be repaired non-destructively in a single command (
palee migrate --fix). - High-concurrency async operations within a single Node.js runtime run without temp-file overwrites.
- Frontmatter formatting remains clean, readable, and 100% compliant with standard YAML parsers.
- Review intervals and due dates compute deterministically regardless of local timezone or historical dates.
- Vault notes without schema versions can be repaired non-destructively in a single command (
- Negative / Tradeoffs:
- Adds a small cryptographic entropy generation step per atomic write.
Alternatives Considered
- Implicit On-the-Fly Schema Upgrades during All Read Commands:
- Why Rejected: Automatic mutation on reading violates the read-only idempotency invariant of
next,plan, andprogresscommands.
- Why Rejected: Automatic mutation on reading violates the read-only idempotency invariant of
- Global Single-Threaded Write Mutex:
- Why Rejected: Unnecessarily serializes distinct file writes across separate subdirectories, degrading throughput on large vault batches.
