docs/RELIABILITY.md

RELIABILITY.md

Tranzfer Reliability Contract

A transfer is not fragile.

Once Tranzfer has successfully moved bytes, ordinary failure should not make the user move those bytes again.

If Tranzfer has already moved 220 GB of a 350 GB project, the default outcome after failure is:

continue from roughly 220 GB.

Not:

start from zero.

This document is the reliability contract for Tranzfer.

SOUL.md explains what kind of product Tranzfer is.

STACK.md explains which tools we use.

This file explains what must remain true when everything goes wrong.

Any code touching uploads, downloads, transfer persistence, multipart state, recovery, verification, cleanup, or resumability must preserve the invariants in this document.

Reliability is not a later hardening phase.

Reliability is the product.


1. The promise

Tranzfer exists to move enormous files between people without making them babysit transport.

The user is allowed to have an unreliable environment.

Their Wi-Fi can disappear. Their ISP can flap. Their router can reboot. Their laptop can sleep. Their browser can refresh. Their tab can close. Their browser can restart. Their machine can reboot. A signed URL can expire. A multipart part can fail. An API can briefly return an error. A renderer can crash. The UI can disappear. A transfer can be 63% complete when any of this happens.

Tranzfer is responsible for making ordinary failure boring.

The product should behave as though the transfer is a durable job that happens to be observed by a UI.

The UI is not the job.

The browser tab is not the job.

The Electron window is not the job.

The current JavaScript process is not the job.

The transfer is the job.


2. The prime directive

Never make the user upload bytes again if Tranzfer can prove those bytes already exist correctly on the remote side.

This does not mean blindly trusting stale local state.

It means:

  1. persist enough identity to recover the transfer;
  2. ask the remote system what actually exists;
  3. verify the local file is still the same file;
  4. reconcile the two;
  5. continue only the missing work.

If correctness and convenience conflict, correctness wins.

A resume that silently corrupts a file is worse than a restart.


3. Hierarchy of truth

For browser uploads:

text
1Cloudflare R2 multipart state
2 ↑
3 │ remote truth
4 │
5IndexedDB durable session metadata
6 ↑
7 │ local durable recovery state
8 │
9Uppy runtime
10 ↑
11 │ current process/session
12 │
13Solid 2 UI

For future desktop uploads:

text
1Cloudflare R2 multipart state
2 ↑
3SQLite durable transfer state
4 ↑
5Background transfer engine
6 ↑
7Electron + Solid UI

The closer a layer is to the actual bytes, the more authoritative it is.

The UI must never become durable truth.

A signal, store, memo, query cache, or renderer state must never be the only place where critical recovery information exists.


4. Reliability invariants

These are product invariants, not implementation suggestions.

4.1 Remote completed parts are authoritative

If R2 reports that part 842 exists for the current multipart upload, that is stronger evidence than a stale local progress bar claiming only 841 parts completed.

Local progress can be wrong.

Remote multipart state is the source of truth for uploaded parts.

4.2 Durable metadata must be sufficient to recover

An in-progress transfer must persist enough information to reconstruct its identity after process loss.

Conceptually:

ts
1type DurableUploadSession = {
2 transferId: string;
3 objectKey: string;
4 multipartUploadId: string;
5
6 fileName: string;
7 fileSize: number;
8 lastModified: number | null;
9 fingerprint: string;
10
11 chunkSize: number;
12
13 createdAt: number;
14 updatedAt: number;
15
16 status: "preparing" | "uploading" | "paused" | "recovering" | "finalizing";
17};

The shape may evolve.

The invariant does not.

4.3 Never resume against an unverified local file

If the user replaces Episode42.mov after 180 GB has already uploaded, Tranzfer must not blindly combine the old first 180 GB with the new remainder.

Before resuming after restoration, verify the local file using multiple signals:

text
1name
2size
3last modified time where meaningful
4stable fingerprint

Do not resume when identity is uncertain.

4.4 Filename is not identity

Two files can share a name, extension, or size.

Identity must be stronger than any one of those.

4.5 Retry only failed work

A failed part must not cause successful parts to be uploaded again.

A temporary signing failure must not reset the multipart upload.

A temporary API failure must not destroy the transfer.

4.6 Expired authorization is recoverable

Expired signed URLs or temporary credentials are expected.

The behavior should be:

text
1authorization expires
2 ↓
3obtain fresh authorization
4 ↓
5retry the affected operation

Not:

text
1authorization expires
2 ↓
3restart 300 GB file

4.7 Network disappearance is a pause

A lost connection is ordinary behavior.

The product should say:

Connection lost. Waiting to continue.

When connectivity returns, continue automatically wherever safe.

4.8 Completion is idempotent

This must be safe:

text
1all parts uploaded
2 ↓
3CompleteMultipartUpload sent
4 ↓
5remote object completes
6 ↓
7client crashes before response arrives
8 ↓
9client restarts

Recovery must converge toward the same correct completed state.

4.9 Abort is explicit

Do not silently abort a valid multipart upload because:

text
1tab closed
2window closed
3renderer crashed
4network disappeared

Those are not cancellation.

Cancellation is a deliberate product action.

4.10 Recovery reconciles; it does not assume

Compare durable local state with remote multipart state.

Remote state wins disagreements about uploaded parts.

4.11 Transfers outlive processes

Browser runtime dies: transfer survives.

Renderer dies: transfer survives.

Desktop UI closes: transfer survives.

Machine reboots: transfer survives if the platform can reconnect to the same local file.

4.12 Progress reflects real work

Do not fake progress.

Do not report complete merely because the last part upload finished.

A transfer is complete only after remote completion and Tranzfer state safely reconcile.

4.13 Reliability degrades honestly

If automatic file access cannot be restored, ask the user to reselect the original file and continue.

Never pretend a guarantee exists when the platform cannot provide it.


5. What “resume” means

Do not use the word loosely.

Level 0 — retry

A single request failed. Retry it.

Level 1 — network resume

Connectivity disappears while the runtime remains alive. Continue when it returns.

Level 2 — runtime resume

Refresh or renderer reload. Reconstruct and continue.

Level 3 — browser-session resume

Browser/tab closes. Restore durable session metadata and recover file access where possible.

Level 4 — machine-reboot resume

The OS restarts.

On web:

text
1restore durable session
2 ↓
3restore persistent file handle if possible
4 ↓
5otherwise reselect same file
6 ↓
7verify identity
8 ↓
9ListParts
10 ↓
11resume missing work

On desktop:

text
1restore local path
2verify file
3reconcile remote parts
4continue

Level 5 — unattended desktop resume

Future target:

text
1machine reboots
2 ↓
3background agent starts
4 ↓
5unfinished transfer found
6 ↓
7file still matches
8 ↓
9remote multipart state reconciled
10 ↓
11transfer continues without opening the UI

Do not promise a level before we have actually tortured it.


6. Browser reliability contract

Browser uploads live under browser security constraints.

Do not pretend otherwise.

6.1 Durable browser state

Persist unfinished transfer metadata in IndexedDB or equivalent durable browser storage.

Persist:

text
1transfer identity
2multipart upload identity
3remote object key
4file identity metadata
5fingerprint
6chunk policy
7recovery status
8timestamps
9file-system handle when supported
10schema version

Solid signals are not persistence.

Uppy runtime state is not persistence.

Local variables are not persistence.

6.2 Persistent file handles

Where supported, store a file-system handle durably.

On restoration:

text
1restore handle
2 ↓
3check permission
4 ↓
5request permission through user gesture if required
6 ↓
7obtain File
8 ↓
9verify identity
10 ↓
11reconcile multipart state
12 ↓
13resume

A permission prompt is not a transfer failure.

6.3 Reselect fallback

If file access cannot be restored:

text
1unfinished transfer detected
2 ↓
3show expected file
4 ↓
5user selects local file
6 ↓
7verify identity
8 ↓
9resume existing multipart upload

The user should not restart merely because browser file access was lost.

6.4 Golden Retriever

Uppy Golden Retriever may be used as an extra recovery layer for:

text
1selected file recovery
2runtime state restoration
3accidental refresh
4tab closure

It is not the entire durability design.

Our own durable transfer identity must exist independently.

6.5 Capability tiers

Internally classify browser recovery capability.

Example:

text
1Tier A
2persistent file handle available
3strongest automatic recovery
4
5Tier B
6durable session available
7file must be reselected
8
9Tier C
10limited browser APIs
11best-effort recovery with explicit limitations

Never silently downgrade.


7. Desktop reliability contract

The desktop app exists partly because native processes can provide stronger long-running guarantees.

7.1 Electron is the shell

Assume Electron unless product reality changes it.

Electron owns:

text
1window lifecycle
2tray
3menus
4native notifications
5updater
6OS integration
7IPC bridge

Electron does not own the transfer engine.

7.2 Background transfer engine

Initial assumption:

text
1compiled Bun sidecar process

Responsibilities:

text
1filesystem reads
2multipart upload
3durable queue
4SQLite
5retries/backoff
6network recovery
7bandwidth policy
8sleep/wake recovery
9remote reconciliation
10finalization

The renderer may disappear without affecting upload correctness.

7.3 Renderer independence

Ideal:

text
1user closes Tranzfer window
2 ↓
3renderer dies
4 ↓
5minimal Electron shell remains
6 ↓
7Bun uploader keeps transferring

When the UI returns:

text
1renderer starts
2 ↓
3requests current snapshot
4 ↓
5projects daemon state

7.4 Desktop durable database

Conceptually:

sql
1uploads
2-------
3id
4transfer_id
5local_path
6file_name
7file_size
8last_modified
9fingerprint
10remote_key
11multipart_upload_id
12chunk_size
13status
14created_at
15updated_at

and optionally:

sql
1parts
2-----
3upload_id
4part_number
5etag
6size
7completed_at

Exact schema may change.

The recovery capability may not.

7.5 Remote truth still wins

SQLite accelerates recovery.

R2 confirms reality.

7.6 Bun is not sacred

If profiling shows unacceptable RAM, CPU, battery use, missing OS behavior, or reliability problems, replace only the daemon boundary.

A future Rust daemon must not require rewriting the renderer, API, contracts, or transfer UX.


8. Multipart design

Multipart is the basis of giant-file resumability.

8.1 Huge files use multipart

Do not upload 300 GB as one enormous request.

8.2 Chunk size is derived

Never hardcode a chunk size that can exceed the provider's multipart part-count limit.

A reasonable starting policy may be approximately:

text
1large files ~64 MiB
2hundreds of GB ~128 MiB
3very large files ~256 MiB

Benchmark before canonizing values.

8.3 Trade-off

Smaller parts:

text
1+ less retransmission on failure
2+ finer resume granularity
3- more requests
4- more signing operations
5- more bookkeeping

Larger parts:

text
1+ fewer requests
2+ less control-plane chatter
3- more retransmission per failed part
4- coarser recovery

8.4 No presigning the whole future

Do not generate thousands of part URLs at transfer start.

Long-running transfers can outlive them.

Sign lazily or use another safe short-lived credential strategy.

8.5 Stable object identity

Once multipart creation fixes the remote object identity, resumed operations must continue against that same object.

8.6 ListParts is core infrastructure

Use it after uncertain interruption.

Use it when local and remote state may disagree.

Use it before deciding what to resend.


9. File identity and fingerprinting

Resuming the wrong file is corruption.

Treat file identity as a first-class domain concept.

Persist:

text
1name
2size
3lastModified when available
4fingerprint
5fingerprint algorithm version

The fingerprint should detect accidental replacement without requiring a complete 350 GB reread before every resume.

A possible sampled strategy:

text
1hash(
2 metadata
3 +
4 beginning sample
5 +
6 deterministic interior samples
7 +
8 end sample
9)

The exact algorithm may evolve.

A full checksum may be computed incrementally while bytes are already being read.

Do not repeatedly re-hash giant files without reason.


10. State machines, not boolean soup

Do not model upload lifecycle as unrelated booleans that can contradict one another.

Prefer explicit tagged states.

Example:

ts
1type TransferState =
2 | { tag: "preparing" }
3 | { tag: "waiting-for-file-access" }
4 | { tag: "verifying-local-file" }
5 | { tag: "creating-multipart" }
6 | { tag: "uploading"; progress: Progress }
7 | { tag: "offline"; progress: Progress }
8 | { tag: "paused"; progress: Progress }
9 | { tag: "retrying"; attempt: number; progress: Progress }
10 | { tag: "recovering" }
11 | { tag: "reconciling-parts" }
12 | { tag: "finalizing" }
13 | { tag: "verifying-remote-object" }
14 | { tag: "complete"; transferId: string }
15 | { tag: "cancelled" }
16 | { tag: "failed"; error: TransferError };

Use Effect Match / tagged enums where exhaustive matching improves clarity.


11. Recovery state machine

Recovery is not one boolean.

Conceptually:

text
1load durable session
2 ↓
3does transfer still exist?
4 ↓
5can local file be opened?
6 ↓
7does local file still match?
8 ↓
9does multipart upload still exist?
10 ↓
11ListParts
12 ↓
13reconcile
14 ↓
15resume

Possible states:

ts
1type RecoveryState =
2 | { tag: "loading-session" }
3 | { tag: "needs-permission" }
4 | { tag: "needs-file-reselection" }
5 | { tag: "verifying-file" }
6 | { tag: "remote-upload-expired" }
7 | { tag: "reconciling-parts" }
8 | { tag: "ready-to-resume" }
9 | { tag: "resuming" }
10 | { tag: "file-changed" }
11 | { tag: "already-complete" }
12 | { tag: "failed"; error: RecoveryError };

Solid projects these states.

Solid does not invent them independently.


12. Failure taxonomy

Not all failures are equal.

Retryable transport failure

Examples:

text
1temporary network loss
2timeout
3429
45xx
5temporary storage issue

Behavior:

text
1retry with bounded backoff
2preserve session
3do not restart whole file

Authorization expiry

Behavior:

text
1refresh authorization
2retry operation

User attention required

Examples:

text
1file permission lost
2file handle unavailable
3local path moved
4external drive disconnected

Behavior:

text
1pause safely
2preserve remote progress
3ask for the smallest possible user action

Local file mismatch

Behavior:

text
1do not resume
2explain why
3offer safe restart

Remote multipart expired

Behavior:

text
1do not pretend resume remains possible
2explain clearly
3start fresh only through explicit product logic

Finalization uncertainty

Behavior:

text
1inspect remote object
2reconcile transfer status
3converge idempotently

Fatal invariant failure

Behavior:

text
1capture diagnostics
2fail loudly
3do not continue with questionable data

13. Progress, speed, and ETA

The progress bar is part of trust.

Progress must represent confirmed work.

Speed should be smoothed enough to be useful.

ETA should be honest, not absurdly precise.

Prefer:

text
1~18 min remaining

over:

text
117m 42.381s

If bytes are done but finalization is not:

text
1Uploading 100%
2Finalizing...

Do not call the transfer complete early.


14. Persistence rules

Persist valuable identity before proceeding into work that would be difficult to rediscover.

If multipart upload creation succeeds, do not rely on volatile memory as the only place that knows its identity.

Prefer small, atomic durable checkpoints.

Persist domain recovery state, not giant runtime blobs.

Version persisted schemas:

ts
1{
2 schemaVersion: 1,
3 ...
4}

A user may begin a transfer on frontend version N and resume on version N+1.

Do not casually make deployed in-progress transfers unreadable.


15. Cleanup

Incomplete multipart uploads consume remote resources.

Stale sessions must eventually be aborted.

But cleanup must respect the advertised resume window.

Never promise:

Resume within 7 days

while maintenance aborts the session after 24 hours.

Product semantics and lifecycle policy must agree.

Closing the UI is not cleanup.

Losing the network is not cleanup.

Explicit cancellation, expiry, and confirmed abandonment are cleanup events.


16. Cancellation

Cancel is destructive.

A true cancellation may:

text
1stop active work
2abort multipart upload
3free transfer capacity
4remove durable recovery metadata
5mark transfer cancelled

Do not trigger this sequence because a renderer disappears.


17. Security during resume

Resume is not an authorization bypass.

The API must still verify:

text
1identity
2transfer ownership
3workspace membership
4entitlement
5transfer status
6object-key ownership
7multipart-upload association

A client must never be able to present an arbitrary uploadId and receive signed access to arbitrary storage objects.


18. Integrity after completion

Completion is more than one successful API response.

At minimum reconcile:

text
1object exists
2expected size
3transfer record matches object
4upload session is complete
5capacity/accounting is correct
6recipient availability is correct

Where stronger checksums are useful and affordable, add them.


19. Download reliability

Uploads come first, but the philosophy applies in reverse.

A future desktop receiver should support:

text
1background download
2resume
3bandwidth limits
4destination rules
5disk-space checks
6checksum verification
7post-download remote cleanup

The invariant remains:

already downloaded bytes should not be needlessly downloaded again.


20. Resource safety

Do not buffer giant files in memory.

Memory usage should scale with:

text
1concurrency × bounded part size

not:

text
1total file size

Respect backpressure.

Do not leak file descriptors over multi-hour transfers.

Do not repeatedly reread or rehash hundreds of gigabytes without a clear reason.


21. Sleep, wake, and network changes

Sleep is normal laptop behavior.

On wake:

text
1check connectivity
2refresh authorization if needed
3reconcile uncertain work
4continue

Network transitions are normal too:

text
1Ethernet → Wi‑Fi
2Wi‑Fi → hotspot
3VPN on/off
4home → office

Temporary transition may pause throughput.

It should not require restarting the transfer.


22. Uppy responsibilities

Uppy owns browser upload mechanics.

That includes the mechanics around:

text
1multipart orchestration
2part uploads
3retry/backoff
4pause/resume
5progress
6remote part listing
7completion
8abort

Tranzfer owns:

text
1transfer identity
2quota
3durable session identity
4same-file verification
5recovery UX
6authorization
7business lifecycle
8telemetry
9final verification
10abuse controls
11acceptance testing

Do not reimplement Uppy for sport.

Do not assume Uppy automatically solves every product-level recovery requirement.


23. Solid 2 responsibilities

Solid owns reactive presentation and orchestration.

Solid does not own durable correctness.

Good:

text
1durable recovery service
2 ↓
3reactive state
4 ↓
5Solid UI

Bad:

text
1Solid signal
2 ↓
3effect
4 ↓
5hope it persisted

Derive whenever possible.

Effects are for external side effects, not synchronizing multiple copies of the same domain state.

Component destruction must always be safe.


24. Desktop renderer responsibilities

The desktop renderer may:

text
1display progress
2display speed
3display ETA
4display errors
5request pause
6request resume
7request cancellation
8show recovery prompts

It must not be the only owner of:

text
1local file path
2multipart uploadId
3durable queue
4retry policy
5remote reconciliation

25. Background daemon responsibilities

The background transfer engine must be reconstructible from:

text
1local durable database
2+
3local filesystem
4+
5remote storage state
6+
7Tranzfer API

It must not require the renderer to explain what it was doing before a crash.


26. Observability

Record meaningful events such as:

text
1transfer_created
2multipart_created
3part_retry
4network_offline
5network_restored
6auth_refreshed
7tab_recovery_started
8file_permission_required
9file_reselected
10file_identity_mismatch
11parts_reconciled
12resume_started
13resume_succeeded
14resume_failed
15finalization_started
16finalization_retried
17transfer_completed
18transfer_cancelled
19multipart_expired

Never log raw credentials, signed URLs, private tokens, or file contents.


27. Reliability metrics

Eventually measure:

text
1successful transfer rate
2successful resume rate
3manual-intervention rate
4avoidable bytes re-uploaded
5average retries per large transfer
6finalization failure rate
7reselection frequency
8file mismatch frequency
9multipart expiry frequency
10time from recovery to resumed throughput

A particularly important metric is:

avoidable re-uploaded bytes

If a user successfully moved 217 GB and Tranzfer unnecessarily makes them resend 217 GB, that is a serious product failure.


28. Recovery UX

Recovery should feel calm.

Example:

text
1Episode 42
2347 GB
3
4Found unfinished transfer
5217 GB already uploaded
6
7[Continue]

If permission is required:

text
1217 GB is already uploaded.
2
3Allow access to the original file to continue.
4
5[Allow & continue]

If reselection is required:

text
1Select the original Episode42.mov to continue.
2Already uploaded data will not be sent again.
3
4[Choose file]

If the file changed:

text
1This file no longer matches the upload that started earlier.
2
3To protect your footage, Tranzfer won't combine two different file versions.
4
5[Start a new transfer]

Do not expose ListMultipartUploadParts, SigV4, IndexedDB, ETags, or other infrastructure jargon to users.


29. No fake heroics

If we cannot prove the local file is the same file: stop.

If the remote multipart session no longer exists: say so.

If storage returns a state we do not understand: fail safely.

Reliability means trustworthy continuation, not aggressive continuation at all costs.


30. Torture testing is product development

Mocked tests are necessary.

They are not sufficient.

The product's value is surviving real failure, so we must create real failure.

Required baseline file sizes:

text
110 GB
2100 GB
3350 GB

Later add 500 GB and 1 TB when real usage and plan limits justify it.


31. Browser torture matrix

For a serious 350 GB test:

Connectivity

  • disconnect Wi‑Fi mid-part
  • reconnect after 30 seconds
  • reconnect after 10 minutes
  • switch networks mid-transfer
  • restart router
  • temporary DNS failure
  • connection becomes dramatically slower

Request failures

  • force a part to return 429
  • force a part to return 500
  • force several consecutive retryable failures
  • signing endpoint 500
  • signing endpoint timeout
  • signed authorization expiry
  • failure immediately before finalization
  • lost response immediately after finalization

Browser lifecycle

  • refresh at 1%
  • refresh at 40%
  • refresh at 99%
  • close tab at 30%
  • close tab at 70%
  • reopen site
  • close browser
  • reopen browser
  • browser crash if reproducible
  • PC reboot
  • sleep laptop
  • wake laptop

File access

  • persistent file handle remains valid
  • permission must be requested again
  • handle unavailable
  • reselect original file
  • reselect wrong file
  • reselect same-name different file
  • original file moved
  • original file deleted
  • original file modified

Remote reconciliation

  • local state misses a completed remote part
  • local state claims completion but remote does not
  • stale local progress
  • multipart session expired
  • final object already completed
  • cleanup races with recovery

Completion

  • crash before completion request
  • crash during completion request
  • remote completes but response is lost
  • recovery sees already-completed object
  • duplicate finalization attempt
  • final object size verification

32. Desktop torture matrix

When desktop exists:

  • close renderer while upload continues
  • destroy BrowserWindow entirely
  • Electron shell restart
  • Bun daemon restart
  • kill daemon mid-part
  • OS reboot
  • auto-start after reboot
  • local file path still valid
  • local file moved
  • local file changed
  • external drive unplugged
  • external drive reconnected
  • machine sleep/wake
  • network switch
  • tray-only operation for hours
  • update lifecycle does not destroy active transfers
  • renderer and daemon can reconnect after update
  • incoming download checks free disk space

33. Acceptance standard

A torture test does not pass because the UI looks okay.

It passes only if:

text
1final remote object is correct
2+
3already uploaded valid parts were not needlessly resent
4+
5transfer state converged correctly
6+
7the user could understand what happened

34. Release gates

Gate A — internal

text
110 GB
2network drop
3part retry
4refresh

Gate B — serious beta

text
1100 GB
2tab close
3sleep/wake
4authorization expiry
5recovery

Gate C — Tranzfer reliability promise

text
1350 GB
2router restart
3browser restart
4file reselection recovery
5remote reconciliation
6completion verification

Gate D — reboot promise

text
1350 GB
2machine reboot
3durable restore
4same-file verification
5continue existing multipart upload

Do not market Gate D before Gate D passes.


35. Regression severity

P0

text
1silent file corruption
2security boundary bypass
3wrong user's object resumed

P1

text
1recoverable huge upload restarts from zero
2completed transfer becomes inaccessible
3remote object and product state diverge badly

P2

text
1manual action required where automatic recovery should work
2progress incorrect after recovery
3resume requires unnecessary extra steps

P3

text
1confusing recovery copy
2weird ETA
3cosmetic state issue

36. Agent rules

Every coding agent touching transfer code must know:

text
1R2 remote state is authoritative for uploaded parts.
2Durable metadata outlives UI processes.
3Local file identity must be verified.
4Recovery reconciles; it does not assume.
5Component lifetime must not determine correctness.
6Uppy owns browser upload mechanics.
7Solid owns presentation, not durable transfer truth.

Reject code that:

  • stores critical upload identity only in a component;
  • creates a second upload state machine next to Uppy;
  • aborts uploads on page/window disappearance;
  • assumes unload means cancellation;
  • clears durable state before completion is known;
  • resumes based only on filename;
  • trusts stale local completed-part lists without reconciliation;
  • treats every error as fatal;
  • restarts a whole file after one failed part;
  • pre-signs thousands of future part URLs;
  • hardcodes chunk size without part-limit reasoning;
  • marks complete before finalization;
  • swallows completion uncertainty;
  • logs signed URLs or credentials.

37. Code-review questions

Every upload/recovery PR should answer:

  1. What durable state does this change create?
  2. What happens if the process dies immediately afterward?
  3. What if the remote operation succeeded but the response is lost?
  4. What if local and remote state disagree?
  5. What if the local file changed?
  6. Can the user be forced to resend already-confirmed bytes?
  7. Does cancellation remain explicit?
  8. Can this survive refresh?
  9. Can this survive browser restart?
  10. Can this survive machine reboot?
  11. Does it preserve future desktop compatibility?
  12. What torture test proves it?

38. Definition of done: browser uploader

The browser uploader is not done because a 1 GB happy path reaches R2.

It is done when:

  • 10 GB works
  • 100 GB works
  • 350 GB works
  • chunk policy respects multipart limits
  • progress is accurate
  • retryable errors retry
  • network loss recovers
  • refresh recovers
  • tab close recovers
  • browser restart has a recovery path
  • PC reboot has a recovery path
  • file permission loss has a recovery path
  • original file reselection safely resumes
  • changed file is rejected
  • remote parts reconcile
  • authorization can refresh
  • finalization is safe
  • final object is verified
  • cancellation cleans up intentionally
  • stale sessions eventually clean up

39. Definition of done: desktop uploader

Desktop upload is not done because Electron can upload a file.

It is done when:

  • renderer may disappear without stopping upload
  • daemon state survives daemon restart
  • machine reboot resumes
  • local file is verified
  • changed file is rejected
  • remote state reconciles
  • tray-only transfer works for hours
  • sleep/wake works
  • network switch works
  • external-drive loss is handled safely
  • update lifecycle does not destroy active transfers
  • resource usage is acceptable

40. What we explicitly do not build yet

Reliability is not permission to build a storage operating system.

Do not build yet:

text
1mounted filesystem
2Dropbox-style sync
3folder mirroring
4distributed block deduplication
5peer-to-peer transport
6custom TCP protocol
7custom congestion control
8global accelerator network
9bespoke multipart protocol
10enterprise transfer appliance

Use existing infrastructure.

S3-compatible multipart already solves the core remote resumability primitive.

Uppy already solves much of browser transfer mechanics.

R2 already stores the parts.

We build the product semantics and recovery experience around those primitives.


41. Anti-overengineering rule

When deciding between:

text
1beautiful generic transfer abstraction

and:

text
1350 GB upload survives router restart

choose the second one.

When deciding between:

text
1five-backend portable storage adapter

and:

text
1R2 resume works after browser restart

choose the second one.

When deciding between:

text
1perfect event-sourced upload architecture

and:

text
1real editor resumes a failed upload

choose the second one.


42. Anti-underengineering rule

“Don't overengineer” is not permission to ship fragile uploads.

These are not optional polish:

text
1multipart
2retry
3durable upload identity
4reconciliation
5same-file verification
6safe finalization
7real torture testing

For Tranzfer, these are the minimum product.


43. The 350 GB rule

Every upload architecture proposal must explain this scenario:

text
1A creator has a 350 GB project.
2
3They start uploading at night.
4
5At 63%:
6the router restarts.
7
8Ten minutes later:
9the network returns.
10
11At 71%:
12the laptop sleeps.
13
14In the morning:
15the laptop wakes.
16
17At 79%:
18the browser is accidentally closed.
19
20Later:
21the computer reboots for an update.
22
23The creator opens Tranzfer again.
24
25Tranzfer finds the unfinished transfer.
26
27It restores or requests access to the original file.
28
29It verifies the file is unchanged.
30
31It asks R2 which parts already exist.
32
33It continues from the missing work.
34
35The creator does not resend 276 GB.
36
37The editor eventually receives one correct file.

If a design cannot explain exactly how this works, the design is incomplete.


44. The already-moved-bytes rule

Already moved bytes are an asset. Preserve them.

Every retry strategy, persistence decision, cleanup policy, and UX flow should respect that.


45. The one-file rule

A multipart object must correspond to one immutable logical source-file version.

Do not combine versions.

Do not guess.

One logical transfer.

One logical source file.

One final object.


46. The remote-truth rule

When recovering:

text
1local says 72%
2remote says 74%

remote wins.

When:

text
1local says part 1200 done
2remote does not have part 1200

upload part 1200 again.

When:

text
1local says finalizing
2remote object already exists correctly

converge toward complete.


47. The calm-software rule

Failures should not make the product scream.

Prefer:

text
1Connection lost.
2We'll continue when you're back online.

or:

text
1We need access to the original file to continue.
2217 GB is already uploaded.

The product should communicate confidence because the system actually has a recovery plan.


48. Reliability ladder

text
1happy-path upload
2 ↓
3part retry
4 ↓
5network recovery
6 ↓
7refresh recovery
8 ↓
9tab/browser recovery
10 ↓
11machine-reboot recovery
12 ↓
13background desktop transfer
14 ↓
15unattended recurring delivery

Do not skip lower rungs.


49. Reliability before automation

Automation amplifies whatever reliability exists underneath.

If transfer is fragile:

text
1automation = automated failure

Therefore:

text
1reliable transfer
2 ↓
3background transfer
4 ↓
5trusted relationships
6 ↓
7automatic delivery

50. Reliability before everything else

Review features are irrelevant if the file never arrives.

Pricing sophistication is irrelevant if a 300 GB transfer restarts from zero.

Desktop architecture is irrelevant if browser reliability has not taught us the actual failure modes.

Scale is irrelevant before ten users trust us with real footage.

Reliability comes first.


51. Product copy constraints

Do not claim:

Never fails.

Nothing never fails.

Claim things we can prove.

Examples:

text
1Resumes interrupted transfers.
2
3Already uploaded parts stay uploaded.
4
5Lose Wi‑Fi. Pick up where you left off.
6
7Reopen Tranzfer and continue.
8
9No starting a 300 GB project from zero because your connection blinked.

Only market stronger claims after the corresponding release gate passes.


52. The customer's mental model

The customer should think:

Tranzfer remembers.

Not:

I hope the tab stays open.


53. The engineering mental model

Engineers and agents should think:

A transfer is a durable distributed job with a local source file and remote multipart state.

Not:

A transfer is a component with a progress bar.


54. The founder mental model

Do not turn reliability into another way to avoid customers.

The purpose of this document is to make Tranzfer trustworthy enough for real people to use.

It is not permission to spend three months perfecting theoretical failure modes nobody has encountered.

The sequence remains:

text
1build
2break
3fix
4real human
5repeat
6ask for money

55. Final standard

Tranzfer should eventually be the software someone chooses when the file is too important and too large to casually try again.

The connection may fail.

The browser may disappear.

The process may die.

The machine may reboot.

The transfer should remain understandable, recoverable, and safe.

The best reliability feature is not a clever retry algorithm.

It is the user's belief, earned by repeated evidence, that:

I can leave this alone. Tranzfer will get it there.

Until that is true:

make the next transfer more reliable than the last one.