# Fileserver Durable Recovery Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this > plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. Repository policy is > human-only, so no step stages or commits changes. **Goal:** Make the local publication provider restart-safe for completed and sealed operations without re-running the row producer. **Architecture:** Keep the application port unchanged. The adapter owns a private operation journal under `.ca-fileserver/operations`, writes records through forced temp files and atomic rename, and uses a deterministic request fingerprint. A retry restores a verified terminal receipt or resumes a sealed staged artifact; disagreement is a conflict or indeterminate outcome, never an overwrite. **Tech Stack:** Java 21 NIO, JUnit 5, AssertJ, existing Gradle quality gates. --- ### Task 1: Define deterministic journal records and request fingerprints **Files:** - Create: `src/adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPublicationJournalRecord.java` - Create: `src/adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPublicationJournalCodec.java` - Create: `src/adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/FilePublishRequestFingerprint.java` - Test: `src/adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver/LocalPublicationJournalTest.java` - [x] Write a failing test proving stable request fingerprints and different fingerprints for source/schema changes. - [x] Write a failing test proving journal round-trip and rejection of corrupt/newer records. - [x] Run `./gradlew :adapter:outbound:fileserver:test --tests '*LocalPublicationJournalTest' --console=plain` and confirm the missing types fail compilation. - [x] Implement a bounded flat JSON codec with schema version, state, fingerprint, locator token, checksum/counts and receipt snapshot fields. It must reject duplicate/unknown keys and never serialize absolute paths or row data. - [x] Run the focused test and confirm GREEN. ### Task 2: Add forced atomic journal persistence and recovery **Files:** - Create: `src/adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPublicationJournal.java` - Modify: `src/adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalFilePublicationAdapter.java` - Test: `src/adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver/LocalFilePublicationRecoveryTest.java` - [x] Write a failing test where a completed operation is retried with a producer that throws; the original receipt must be returned and the producer must remain uncalled. - [x] Write a failing test that reconstructs a new adapter over a sealed journal plus staged bytes and resumes publication without calling the producer. - [x] Write a failing test proving the same operation ID with a different request is a conflict and a digest mismatch is indeterminate. - [x] Run the recovery test and confirm RED. - [x] Persist `WRITING`, `SEALED`, and `PUBLISHED` records with temp + force + atomic move. Verify the target size and SHA-256 before terminal reconstruction. - [x] Run all Fileserver tests and confirm GREEN. ### Task 3: Report the exact readiness boundary **Files:** - Modify: `src/adapter/outbound/fileserver/README.md` - Modify: `src/adapter/outbound/fileserver/CLAUDE.md` - Modify: `docs/superpowers/specs/2026-07-26-fileserver-production-capability-design.md` - [x] Mark single-node local restart recovery as implemented. - [x] Keep multi-node fencing, bounded background reaper, SFTP, NFS and HA evidence explicitly unimplemented. - [x] Run `./gradlew :adapter:outbound:fileserver:check --console=plain`.