copia 0.2.0

Pure Rust rsync-style delta synchronization library
Documentation
metadata:
  version: "1.0.0"
  created: "2026-07-04"
  author: "PAIML Engineering"
  description: "Recursive local->remote directory push: structure preservation + byte fidelity (mirror of recursive-remote-pull)"
  references:
    - "Symmetric with run_sync_dir(TransferDir::Pull) — the remote->local path proven by recursive-remote-pull-v1"
    - "Tridgell (1999) Efficient Algorithms for Sorting and Synchronization (rsync) — recursive tree transfer"

equations:
  push_structure_preservation:
    formula: "relpaths(push(local_root)) = relpaths(local_tree(local_root))"
    domain: "local_root is a readable local directory tree"
    invariants:
      - "Every local file lands at the same path relative to the remote destination root"
      - "Nested subdirectories are created remotely (mkdir -p) before their files are written"
      - "Symlinked directories are not descended into (discover_local_files skips is_symlink dirs)"
  push_byte_fidelity:
    formula: "sha256(remote(root/p)) = sha256(local(local_root/p))"
    domain: "p in relpaths(local_tree)"
    codomain: "equal digests"
    invariants:
      - "Each pushed file is byte-for-byte identical to its local source (streamed via cat > $'path', not truncated)"
  discover_relativization:
    formula: "discover(root) = sort({ strip_prefix(root, f) : f in files_under(root) })"
    domain: "root is a directory; files_under enumerates regular files recursively"
    codomain: "sorted relative paths"
    invariants:
      - "Discovered paths are relative to root (leading root prefix stripped) and sorted"
      - "Only regular files are emitted; directories and symlink-dirs are not files"

proof_obligations:
  - type: roundtrip
    property: "Push byte fidelity"
    formal: "sha256(remote(p)) == sha256(local(p)) for every pushed file p"
    applies_to: all
  - type: invariant
    property: "Structure preservation"
    formal: "the set of remote relative paths equals the local file set"
    applies_to: all
  - type: invariant
    property: "Discovery relativization"
    formal: "discover_local_files strips the root prefix and returns sorted relative paths"
    applies_to: discover_local_files

falsification_tests:
  - id: FALSIFY-PUSH-001
    rule: "Byte fidelity"
    prediction: "Every pushed file's sha256 matches the local source"
    test: "Push a 3-file tree (text + multi-chunk binary across 2 nested dirs), compare sha256 remote vs local"
    if_fails: "Streaming chunk-boundary corruption or truncation in transfer_file_to_remote"
  - id: FALSIFY-PUSH-002
    rule: "Structure preservation"
    prediction: "Nested subdirs are recreated remotely; each file lands at its correct relative path"
    test: "local sub/deep/big.bin arrives at remote root/sub/deep/big.bin"
    if_fails: "create_remote_dirs missed a parent, or spawn_dir_transfers computed a wrong remote path"
  - id: FALSIFY-PUSH-003
    rule: "Empty tree"
    prediction: "An empty local dir yields zero files and no error"
    test: "discover_local_files over an empty tree returns []; run_sync_dir short-circuits with 'No files found.'"
    if_fails: "discover_local_files errors or emits phantom entries for an empty directory"
  - id: FALSIFY-PUSH-004
    rule: "Discovery relativization"
    prediction: "discover_local_files returns paths relative to root, sorted, files only"
    test: "transfer_tests::discover_and_total_size_over_a_temp_tree (a.txt, sub/b.txt, sorted, dirs excluded)"
    if_fails: "strip_prefix or sort bug, or a directory leaked into the file list"

kani_harnesses:
  - id: push-kani-001
    obligation: "collect_dirs never panics and yields each file's ancestor chain for arbitrary path bytes"
    bound: 4
    strategy: bounded_int

qa_gate:
  id: F-PUSH-001
  name: Recursive Push Contract
  description: Local->remote recursive sync structure preservation + byte fidelity
  checks:
    - push_structure_preservation
    - push_byte_fidelity
    - discover_relativization
  pass_criteria: All 4 falsification tests pass + discovery relativization holds
  falsification: A wrong relative-path computation or a truncated stream breaks structure/byte fidelity