Skip to content

Add BASE64 encoding steps in IPNS publish sequences and bump to v1.9.0#18

Merged
FSM1 merged 2 commits into
feat/spec-hardeningfrom
copilot/sub-pr-4
Jan 18, 2026
Merged

Add BASE64 encoding steps in IPNS publish sequences and bump to v1.9.0#18
FSM1 merged 2 commits into
feat/spec-hardeningfrom
copilot/sub-pr-4

Conversation

Copilot AI commented Jan 18, 2026

Copy link
Copy Markdown
Contributor

Sequence diagrams in DATA_FLOWS.md were missing the BASE64 encoding step between IPNS record signing and submission to the backend relay endpoint. The API specification requires ipnsRecord as a BASE64-encoded string, but diagrams showed direct transmission after Ed25519 signing.

Changes:

  • IPNS Publishing Sequences: Added C->>C: Encode signed record to BASE64 step after every Sign IPNS record (Ed25519) operation in DATA_FLOWS.md (8 locations: file upload, folder create/rename/move/delete, file update)

  • Version Bump: Incremented all documentation from 1.8.2 → 1.9.0 reflecting this architectural clarification

Example (File Upload Flow):

C->>C: Sign IPNS record (Ed25519)
C->>C: Encode signed record to BASE64
C->>B: POST /ipns/publish (signed record)
B->>IPFS: Publish IPNS record
Loading

This aligns sequence diagrams with TECHNICAL_ARCHITECTURE.md (line 430) and the POST /ipns/publish API contract.


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Co-authored-by: FSM1 <12774278+FSM1@users.noreply.github.com>
Copilot AI changed the title [WIP] Add IPFS/IPNS relay endpoint details Add BASE64 encoding steps in IPNS publish sequences and bump to v1.9.0 Jan 18, 2026
Copilot AI requested a review from FSM1 January 18, 2026 01:46
@FSM1 FSM1 marked this pull request as ready for review January 18, 2026 01:49
@FSM1 FSM1 merged commit 5dc1348 into feat/spec-hardening Jan 18, 2026
@FSM1 FSM1 deleted the copilot/sub-pr-4 branch January 18, 2026 01:50
FSM1 added a commit that referenced this pull request Jan 18, 2026
* bump version to 1.8.1 and update documentation for IPFS/IPNS relay integration

* Fix date inconsistency in TECHNICAL_ARCHITECTURE.md (#7)

* Initial plan

* Fix date inconsistency in TECHNICAL_ARCHITECTURE.md

Co-authored-by: FSM1 <12774278+FSM1@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: FSM1 <12774278+FSM1@users.noreply.github.com>

* Fix date inconsistency in DATA_FLOWS.md frontmatter (#8)

* Initial plan

* Fix date inconsistency in DATA_FLOWS.md frontmatter

Co-authored-by: FSM1 <12774278+FSM1@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: FSM1 <12774278+FSM1@users.noreply.github.com>

* Add missing CID return arrows in IPFS/IPNS sequence diagrams (#6)

* Initial plan

* Add missing return arrows in IPFS/IPNS sequence diagrams

Added `B->>C: Return CID` after all `B->>IPFS: Add metadata, return CID` operations to show that the Backend returns the CID to the Client before the Client signs the IPNS record. The Client needs this CID to create the IPNS record that points to it.

Updated 8 sequence diagrams:
- File Upload Flow (IPNS publish)
- Create Folder (empty folder + update parent)
- Rename File/Folder
- Move File/Folder (destination + source)
- Delete File
- Update File Content

Bumped version to 1.8.2

Co-authored-by: FSM1 <12774278+FSM1@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: FSM1 <12774278+FSM1@users.noreply.github.com>

* Add missing Backend→Client CID return flows in IPFS/IPNS sequence diagrams (#5)

* Initial plan

* Add return arrows from Backend to Client in IPFS/IPNS sequence diagrams

Co-authored-by: FSM1 <12774278+FSM1@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: FSM1 <12774278+FSM1@users.noreply.github.com>

* Add missing Backend→Client CID return arrows in IPFS sequence diagrams (#10)

* Initial plan

* Add missing Backend->Client CID return arrows in sequence diagrams

Co-authored-by: FSM1 <12774278+FSM1@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: FSM1 <12774278+FSM1@users.noreply.github.com>

* Add missing CID return step in IPNS publish sequence diagrams (#16)

* Initial plan

* Add missing return CID step in IPNS publish sequences

Co-authored-by: FSM1 <12774278+FSM1@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: FSM1 <12774278+FSM1@users.noreply.github.com>

* Fix date inconsistency in API_SPECIFICATION.md (#14)

* Initial plan

* Fix date inconsistency in API_SPECIFICATION.md

Co-authored-by: FSM1 <12774278+FSM1@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: FSM1 <12774278+FSM1@users.noreply.github.com>

* Fix missing YAML frontmatter delimiter in API_SPECIFICATION.md (#15)

* Initial plan

* Fix YAML frontmatter: add missing opening delimiter to API_SPECIFICATION.md

Co-authored-by: FSM1 <12774278+FSM1@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: FSM1 <12774278+FSM1@users.noreply.github.com>

* Fix missing Backend→Client CID return in IPFS/IPNS sequence diagrams (#11)

* Initial plan

* Fix sequence diagrams: add missing Backend->Client CID return arrows

Co-authored-by: FSM1 <12774278+FSM1@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: FSM1 <12774278+FSM1@users.noreply.github.com>

* Fix missing return arrow in IPNS publishing sequence diagram (#13)

* Initial plan

* Add missing return arrow in IPNS publishing sequence diagram

Co-authored-by: FSM1 <12774278+FSM1@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: FSM1 <12774278+FSM1@users.noreply.github.com>

* Fix date inconsistency in CLIENT_SPECIFICATION.md (#9)

* Initial plan

* Fix date inconsistency in CLIENT_SPECIFICATION.md

Co-authored-by: FSM1 <12774278+FSM1@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: FSM1 <12774278+FSM1@users.noreply.github.com>

* Add missing Backend→Client CID return flows in IPFS metadata upload sequences (#12)

* Initial plan

* Add missing return arrows showing CID returned from backend to client after IPFS metadata upload

Co-authored-by: FSM1 <12774278+FSM1@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: FSM1 <12774278+FSM1@users.noreply.github.com>

* Fix documentation inconsistencies and clarify IPFS/IPNS relay architecture (#17)

* Initial plan

* Fix all PR review feedback items

Co-authored-by: FSM1 <12774278+FSM1@users.noreply.github.com>

* Improve documentation clarity per code review feedback

Co-authored-by: FSM1 <12774278+FSM1@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: FSM1 <12774278+FSM1@users.noreply.github.com>

* Add BASE64 encoding steps in IPNS publish sequences and bump to v1.9.0 (#18)

* Initial plan

* Add BASE64 encoding steps in IPNS sequences and bump version to 1.9.0

Co-authored-by: FSM1 <12774278+FSM1@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: FSM1 <12774278+FSM1@users.noreply.github.com>

* Fix inconsistent indentation in mermaid sequence diagrams (#19)

* Initial plan

* Fix mermaid diagram indentation to use consistent 4-space formatting

Co-authored-by: FSM1 <12774278+FSM1@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: FSM1 <12774278+FSM1@users.noreply.github.com>

---------

Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
FSM1 added a commit that referenced this pull request Mar 29, 2026
Phase 9 items #13-19 all resolved across later phases:
- #13 ThrottlerGuard applied to auth controller
- #14 IPNS URL encoding added in Rust SDK extraction
- #15 Debug eprintln! removed before Phase 9 merge
- #16 Private key console.log removed in Phase 28
- #17 Ed25519 key_bytes zeroized in Rust SDK extraction
- #18 Already marked resolved (PublishCoordinator)
- #19 Sync errors sanitized via sanitize_error()

12 Phase 5 items (#1-12) remain open — all low severity
input validation and defense-in-depth improvements.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: d2581dc98652
FSM1 added a commit that referenced this pull request Mar 29, 2026
* docs: move structured logging to implemented in DEFERRED.md

Phase 28 implemented the structured logging wrapper (lib/logger.ts),
replacing 127 direct console.* calls. All 12 pending todos verified
still pending — no other changes needed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 9faf72d8548e

* docs: mark 7 resolved items in security low-severity backlog

Phase 9 items #13-19 all resolved across later phases:
- #13 ThrottlerGuard applied to auth controller
- #14 IPNS URL encoding added in Rust SDK extraction
- #15 Debug eprintln! removed before Phase 9 merge
- #16 Private key console.log removed in Phase 28
- #17 Ed25519 key_bytes zeroized in Rust SDK extraction
- #18 Already marked resolved (PublishCoordinator)
- #19 Sync errors sanitized via sanitize_error()

12 Phase 5 items (#1-12) remain open — all low severity
input validation and defense-in-depth improvements.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: d2581dc98652

* docs: add Phase 34 E2E Test Expansion & Staging Baselines

Consolidates 6 pending testing todos into a single phase:
- AES-CTR streaming playback E2E tests
- Batch download zip E2E tests
- Media preview E2E test suite
- Shared deleteAccount teardown across all specs
- BYO-IPFS load test baselines on staging
- Staging metrics baselines with Faro instrumentation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: d8dd0c8c05c8

* docs: align DEFERRED.md footer date with header

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: b6a6c2383250

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
FSM1 added a commit that referenced this pull request Jun 15, 2026
Two CodeRabbit findings on PR #491 are pre-existing crash-recovery behaviors
that Phase 45 (#18/#19) deliberately preserved (no-behavior-change), so they are
out of scope for that PR and logged as follow-ups:
- replay IPNS resolve uses cache fallback (transient failure can become Found)
- legacy empty file_meta_ipns_name replay publishes an empty FilePointer

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Entire-Checkpoint: de813b6b4734
FSM1 added a commit that referenced this pull request Jun 15, 2026
Phase 45 (PR #491) implemented all 7 scoped todos but the bookkeeping was never
updated (flagged in 45-VERIFICATION.md). Reconcile:

- Move the 6 fully-delivered todos (#11/#12/#15/#18/#19/#20) pending -> done and tick
  their ROADMAP scope checkboxes.
- Keep #14 (test coverage) in pending: only Tier 1 (durability/replay safety-net tests)
  landed; Tier 2 (read_ops/write_ops handler harness) is still open, so it should be
  picked up on the next run.
- Fold the standalone 2026-06-15 fuse-test-coverage todo into #14 (single source of
  truth): records the fuser ReplySender blocker (vendored fuser doesn't export
  ReplySender, so handler reply objects can't be built in unit tests) and that
  journal_helpers.rs builders are unit-testable now via a make_test_fs helper.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Entire-Checkpoint: a2ff42b91a4a
FSM1 added a commit that referenced this pull request Jun 15, 2026
* docs: add phase 45 - desktop FUSE write-durability cleanup

Entire-Checkpoint: b65081e82eb3

* docs(fuse): research phase 45 - desktop FUSE write-durability cleanup

Entire-Checkpoint: a8fbb9ebd3f7

* docs(45): add validation strategy

Entire-Checkpoint: b3374d7857d7

* docs(45): map code patterns for phase 45

Entire-Checkpoint: 82a8e79b6fbf

* docs(45): create phase plan for desktop FUSE write-durability cleanup

Six plans across five waves covering all 7 scope items (#11/#12/#14/#15/#18/#19/#20).
Tests-first safety net (Plan 01, Wave 1) lands before the no-behavior-change refactors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Entire-Checkpoint: e23c5861ec29

* docs(45): mark research questions resolved and fill validation commands

Entire-Checkpoint: f7d2f6782991

* docs(45): annotate roadmap waves and record planning completion

Entire-Checkpoint: df1c6b9521ed

* test(45-01): add crash/partial/retry-exhaustion durability tests T-45-01/02/03

- crash_mid_write_entry_survives_reload: entry put+not-removed survives
  fresh WriteQueue on same dir (simulates process kill after fsync)
- partial_journal_write_is_skipped_not_panicked: truncated .json file
  is skipped with warn, good entry still returned (V5/T-43-03)
- retry_exhaustion_keeps_failed_entry_on_disk: 4 record_failure calls
  on max_retries=3 queue parks entry as Failed, entry stays on disk (D-09)
- Rule 1 auto-fix: make_temp_queue() now uses pid+counter instead of
  tid+counter to prevent stale inter-run temp dir collisions that caused
  park_on_max_retries to fail with left:2 right:1 under --test-threads=4

Entire-Checkpoint: c3eb9d1ad133

* test(45-01): add replay-skip-failed/folder-key-cache/merge tests T-45-06/07/08

- replay_for_vault_does_not_touch_failed_entries: puts Failed entry, runs
  replay against non-routable API, asserts entry count stays 1 (skip path)
- resolve_folder_key_cache_resolves_shared_parent_once: calls private
  resolve_folder_key twice with root shortcut (folder==root), asserts
  both return identical key bytes; marked for #15 cache extension
- merge_folder_children_unions_new_and_existing: local [existing+new]
  merged with remote [existing], result len==2 and local version wins
- Also applies cargo fmt fixes to crates/sdk/src/queue.rs (import order,
  line-wrap style) so cargo fmt --check passes clean for both crates

Entire-Checkpoint: 4f93a1bd8f6e

* docs(45-01): complete write-durability test safety net plan

Six characterization tests T-45-01/02/03/06/07/08 land and pass green
against current Phase-43/44 code. No production code changed.

Entire-Checkpoint: 604b53361682

* refactor(45-02): extract default_journal_dir and JOURNAL_MAX_RETRIES into shared helper

- Add pub fn default_journal_dir() -> PathBuf and pub const JOURNAL_MAX_RETRIES: u32 = 5
  to apps/desktop/src-tauri/src/fuse/mod.rs
- Route fuse/mod.rs mount path through the shared helper (removes inline dirs chain + literal 5)
- Route commands/sync.rs through crate::fuse::default_journal_dir() + JOURNAL_MAX_RETRIES
- Route fuse/windows/mod.rs (winfsp mount path) through the same shared helper
- Add unit test default_journal_dir_ends_with_cipherbox_cb_journal pinning path tail
- All three WriteQueue::new call sites now use JOURNAL_MAX_RETRIES; no literal 5 remains

Entire-Checkpoint: b92e4fdf5fd3

* docs(45-02): complete extract-journal-dir-helper plan

Entire-Checkpoint: 392261e2fd50

* test(45-03): add RED tests T-45-04 and T-45-04-compat for Option<String> sentinel

- upload_entry_none_ipns_round_trips: builds UploadFile with file_meta_ipns_name: None,
  serializes and deserializes, asserts field is None (T-45-04)
- legacy_empty_string_ipns_loads_as_none: hand-written JSON with legacy empty-string
  value asserts deserializes as None; real name asserts Some(name) (T-45-04-compat)
- Both tests fail to compile until the field type changes to Option<String>

Entire-Checkpoint: 315e60a9eaf7

* feat(45-03): change file_meta_ipns_name to Option<String> with serde compat shim

- Add deser_opt_string helper that maps legacy empty-string sentinel to None
  so pre-Phase-45 on-disk journal entries still deserialize (T-45-03-INT)
- Change JournalOp::UploadFile.file_meta_ipns_name from String to Option<String>
  annotated with #[serde(default, deserialize_with = deser_opt_string)]
- Update make_upload_entry test helper and all test constructors to Some(...)
- 48 cipherbox-sdk tests pass including T-45-04 and T-45-04-compat

Entire-Checkpoint: 7de769e92365

* feat(45-03): propagate Option<String> through fuser, winfsp write paths and replay

- read_ops.rs: remove unwrap_or_default() sentinel; pass file_meta_ipns_name.clone()
  (Option<String>) directly into JournalOp::UploadFile
- windows/write_ops.rs: same change for winfsp write path
- lib.rs: change replay_upload_entry signature to file_meta_ipns_name: Option<&str>;
  wrap per-file IPNS publish block in if let Some(name) = file_meta_ipns_name guard;
  update call site to pass file_meta_ipns_name.as_deref(); update test fixtures to Some(...)
- All 43 fuse tests and 48 sdk tests pass; winfsp build errors are pre-existing macOS
  platform compilation failures unrelated to this change

Entire-Checkpoint: c0bc2abce2ac

* docs(45-03): complete Option<String> sentinel plan summary and state updates

Entire-Checkpoint: 3f89835fbd75

* test(45-04): add RED test T-45-05 not_found_outcome_drives_first_publish

- Asserts NotFound -> is_first_publish=true, seq=0
- Asserts Found(7) -> is_first_publish=false, seq=8
- Asserts Error(_) -> Err propagated (entry retained)
- Fails to compile because IpnsResolveOutcome not yet defined in error.rs

Entire-Checkpoint: 4e9b12148a73

* feat(45-04): add IpnsResolveOutcome enum and resolve_ipns_for_replay wrapper

- Add pub enum IpnsResolveOutcome { Found(u64), NotFound, Error(String) }
  to crates/fuse/src/error.rs with #[derive(Debug)] only (not thiserror)
- Add async fn resolve_ipns_for_replay in lib.rs wrapping resolve_sequence
  and classifying results: Ok->Found, 404/not-found->NotFound, other Err->Error
- Replace .contains(not found) string match in replay_upload_entry with
  typed match on IpnsResolveOutcome (behavior identical: NotFound->seq-0
  first-publish, Error->retain+propagate)
- Bin publish path (spawn_bin_entry_publish:572) intentionally unchanged per scope
- T-45-05 now passes; full fuse suite: 44 passed

Entire-Checkpoint: 5e548fd02038

* docs(45-04): complete typed IpnsResolveOutcome plan summary and state

- Add 45-04-SUMMARY.md with TDD gate compliance and self-check
- Advance STATE.md to Plan 5 of 6, add decisions and metric row
- Mark 45-04-PLAN.md complete in ROADMAP.md

Entire-Checkpoint: dbc0571c3c74

* refactor(45-05): reuse publish_file_metadata and memoize resolve_folder_key in replay

- (#20) Replace 80-line inline encrypt/IPNS-record/TEE-wrap/publish block in
  replay_upload_entry with a single call to the shared publish_file_metadata.
  ECIES-unwrap (Step 1) and is_first_publish decision (F3) stay local; all
  remaining publish steps delegate to the shared function. Added conditional
  use imports to route fuse -> operations::implementation and winfsp (without
  fuse) -> platform::windows::operations::implementation.

- (#15) Add resolve_folder_key_cached wrapper and a root-seeded
  folder_key_cache local to replay_for_vault. replay_mkdir_entry and
  replay_upload_entry take &mut cache and call the cached wrapper; BFS,
  MAX_RESOLVE_NODES cap, and root-shortcut in resolve_folder_key unchanged.

- Extended T-45-07 (resolve_folder_key_cache_resolves_shared_parent_once)
  to exercise resolve_folder_key_cached with a pre-seeded cache and assert
  single-entry cache state after two lookups of the same name.

- All 44 cipherbox-fuse tests pass; cargo check --workspace exit 0.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Entire-Checkpoint: 51d3ff34c129

* docs(45-05): complete publish_file_metadata reuse and resolve_folder_key memoization plan

Entire-Checkpoint: 7af2a2eb32ce

* refactor(fuse): consolidate upload+mkdir journal entry builders into journal_helpers

- Add journal_helpers.rs with build_upload_journal_entry and build_mkdir_journal_entry shared builders
- Wire fuser handle_release and winfsp handle_cleanup to build_upload_journal_entry
- Wire fuser handle_mkdir and winfsp handle_create dir branch to build_mkdir_journal_entry
- Each platform retains its own reply/inode mutations and spawn block
- Preserves WinFsp write_generation increment timing difference (read after bump vs before)
- All 44 crash-recovery tests pass; cargo check --workspace clean; fmt check clean

Entire-Checkpoint: ee0779451bb1

* docs(45-06): complete journal-helpers consolidation plan

Entire-Checkpoint: 546e291bb17d

* docs(45): add code review report with false-positive verdict

Entire-Checkpoint: 266466b97326

* docs(phase-45): complete phase execution

Entire-Checkpoint: 57ccd6146897

* docs(phase-45): add security threat verification

Entire-Checkpoint: 04497394bc91

* docs(phase-45): mark validation nyquist-compliant

Entire-Checkpoint: db4adc7537ce

* refactor(fuse): dedup journal-builder helpers and clarify plaintext invariant

Quality cleanup of the new journal_helpers.rs (no behavior change):
- extract current_unix_ms(), generate_entry_id(), wrap_key_to_hex() to
  remove copy-paste across build_upload_journal_entry / build_mkdir_journal_entry
- drop the dead wrapped_key_hex rename-clone; inline at the struct field
- collapse the duplicate write_generation/parent_ino inode lookups into one
- replace the opaque file_meta_ipns_name.as_ref().and_then(|_| ...) guard with
  an explicit is_none() branch
- correct the module/struct docs: the journal stores ciphertext only, but the
  result struct does carry transient in-memory plaintext for the pending_content
  read-after-write cache (never persisted)

cargo test -p cipherbox-fuse -p cipherbox-sdk green (44 + 48); workspace check clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Entire-Checkpoint: e8b47e2ce945

* fix(fuse): zeroize file key on encryption and wrap error paths

generate_file_key() returns a plain [u8; 32] with no zeroize-on-drop, so an
early `?` return from encrypt_aes_gcm or ecies::wrap_key dropped the raw file
key without clearing it — contradicting the adjacent comment. Clear the key via
clear_bytes before every error return so it is wiped on all paths.

Addresses CodeRabbit review on PR #491.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Entire-Checkpoint: 0813adb9ca40

* docs: capture todos for deferred replay hardening from PR 491 review

Two CodeRabbit findings on PR #491 are pre-existing crash-recovery behaviors
that Phase 45 (#18/#19) deliberately preserved (no-behavior-change), so they are
out of scope for that PR and logged as follow-ups:
- replay IPNS resolve uses cache fallback (transient failure can become Found)
- legacy empty file_meta_ipns_name replay publishes an empty FilePointer

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Entire-Checkpoint: de813b6b4734

* test(fuse): cover the replay IPNS resolve classification predicate

Extract the #19 not-found/404 substring classification out of the async,
network-bound resolve_ipns_for_replay into a pure classify_resolve_outcome(result)
helper, and unit-test it directly (Found / NotFound case-insensitive + 404 /
Error). This pins the brittle substring contract without a live API client and
lifts the one cheaply-coverable untested branch in the replay sequencing path.
Behavior is unchanged — resolve_ipns_for_replay now just wraps the pure helper.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Entire-Checkpoint: 1216bd439684

* fix(fuse): harden mkdir durability — roll back inode on journal failure, replay child IPNS

Address two outside-of-diff CodeRabbit findings on PR #491:

- mkdir inserts the child inode and mutates the parent before building/fsyncing
  the journal entry. On build/put failure the error was returned to the OS but
  the ghost directory was left in the inode table with no durable replay record.
  Roll back via InodeTable::remove on both the fuser and WinFsp paths.

- replay_mkdir_entry only merged the child FolderEntry into the parent; it never
  re-published the child folder's own seq-0 IPNS record. A crash after the
  MkdirPublish fsync but before the live background publish left the parent
  pointing at an unresolvable child IPNS name. Re-publish the child's initial
  empty FolderMetadata idempotently (skip on Found, retain on resolve Error)
  with TEE first-publish enrollment, mirroring the UploadFile replay path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Entire-Checkpoint: d20e047c07cb

* docs: log todo for fuse journal_helpers/read_ops/write_ops test coverage

journal_helpers.rs builders are pure and unit-testable now (needs a make_test_fs
helper). read_ops/write_ops handlers are blocked: they consume concrete fuser
Reply objects, and the vendored fuser does not export ReplySender, so a capturing
sender can't be implemented from cipherbox-fuse. Captures options A/B/C for later.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Entire-Checkpoint: 3310840a0f41

* docs: reconcile Phase 45 todo bookkeeping with shipped work

Phase 45 (PR #491) implemented all 7 scoped todos but the bookkeeping was never
updated (flagged in 45-VERIFICATION.md). Reconcile:

- Move the 6 fully-delivered todos (#11/#12/#15/#18/#19/#20) pending -> done and tick
  their ROADMAP scope checkboxes.
- Keep #14 (test coverage) in pending: only Tier 1 (durability/replay safety-net tests)
  landed; Tier 2 (read_ops/write_ops handler harness) is still open, so it should be
  picked up on the next run.
- Fold the standalone 2026-06-15 fuse-test-coverage todo into #14 (single source of
  truth): records the fuser ReplySender blocker (vendored fuser doesn't export
  ReplySender, so handler reply objects can't be built in unit tests) and that
  journal_helpers.rs builders are unit-testable now via a make_test_fs helper.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Entire-Checkpoint: a2ff42b91a4a

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants