Invariants
These invariants are contracts, not guidelines.
Any change that violates them must be treated as a breaking change to the system.
Each invariant below includes the source location where it is enforced.
Invariant Map

1. Engine Is the Single Orchestrator
UploadEngineImpl is the only layer allowed to create sessions, schedule workers, and control concurrency.
Enforced by:
UploadEngine.ts:47—start<T>()is the only entry point for creating uploadsUploadEngine.ts:31—private queue: UploadQueue— queue is private to engineindex.ts— barrel export exposes onlyUploadEngine, notUploadSessionorUploadWorker
2. UI Independence Is Mandatory
The Upload Engine has zero imports from React, Next.js, or any UI framework.
Enforced by:
- Import graph — no file imports
react,next/router, or any hook - All 12 source files depend only on internal libraries and config
:::tip Verification
grep -r "from 'react'" src/lib/internal/UploadEngine/must return zero results.
:::
3. Completion Is State, Not a Callback
Upload completion is durable state (completed) observable via snapshots and events. The onComplete callback is best-effort.
Enforced by:
UploadSession.ts:112—complete(fileUrl)transitions state tocompletedbefore calling callbackUploadWorker.ts:360—runCompletionHandler()wraps callback in try/catch; callback failure →completion_failedstate, not lost completionUploadStateMachine.ts:58—isTerminalState('completed')returnstrue
4. Explicit State Machine
Every upload follows the STATE_TRANSITIONS map. Illegal transitions throw in development.
Enforced by:
UploadStateMachine.ts:6-28—STATE_TRANSITIONSdefines all 9 × N legal transitionsUploadStateMachine.ts:42—throw new Error('Illegal state transition: "${from}" → "${to}"')UploadSession.ts:198— all state changes go throughtransition(from, to)
5. Single Source of Truth
Each upload is represented by exactly one UploadSession instance. The engine holds the canonical Map<UploadSessionId, UploadSession>.
Enforced by:
UploadEngine.ts:29—private sessions = new Map<UploadSessionId, UploadSession>()UploadSession.ts:21—private snapshot: InternalUploadSnapshot— state is encapsulatedUploadSession.ts:64—getSnapshot()returns the snapshot, not a copy of external state
6. No Shared Mutable State
Upload sessions do not share mutable data. Each session and worker have their own state.
Enforced by:
UploadEngine.ts:29-30— separateMapfor sessions and workers, keyed byUploadSessionIdUploadWorker.ts:24-33— all worker state is private instance fields (planner,completedPartNumbers,pauseRequested, etc.)UploadQueue.ts:23-24—pendingandactivetrack IDs only, not shared session state
7. Pause and Resume Are First-Class
Every upload supports pause and resume as semantic operations with proper state transitions.
Enforced by:
UploadStateMachine.ts—uploading → pausedandpaused → resumingare legal transitionsUploadWorker.ts:59—requestPause()setspauseRequested = trueand aborts controllerUploadWorker.ts:174-175— window loop checkspauseRequestedand throwsPauseErrorUploadWorker.ts:271— chunk loop checkspauseRequestedbefore each chunkUploadEngine.ts:96—resume()creates a new worker and re-enqueues withprioritize()
8. Persistence Guarantees Correctness
Upload state is persisted to sessionStorage after every meaningful state change.
Enforced by:
UploadEngine.ts:201—handleEvent()callstoPersistedState()andUploadPersistence.save()on every eventUploadEngine.ts:137—rehydrateFromPersistence()runs in constructor, restoring sessions on page loadUploadPersistence.ts:59—loadForTenant(site, siteId)ensures tenant-scoped isolation
9. Upload and Domain Are Separate Concerns
The engine transfers files. Domain actions are handled by external listeners.
Enforced by:
index.ts— public surface isUploadEngine+ types; no domain types exportedUploadWorker.ts—completeMultipart()producesfileUrl; does not call domain servicesUploadTypes.ts—UploadContext<T>is generic; engine never inspectsT
10. Completion Handling Is Event-Driven
Completion is delivered as a UPLOAD_COMPLETED event via the Signal bus.
Enforced by:
UploadEvents.ts:6—emitUploadEvent(event)callsSignal.emit('upload', event)UploadEngine.ts:201—handleEvent()receives event from session, publishes to bus- Event delivery is fire-and-forget; engine does not wait for consumer acknowledgment
11. Intent Metadata Is Immutable
UploadContext<T> is set at start() and never mutated.
Enforced by:
UploadSession.ts:40—contextis set in constructor fromargs.contextUploadTypes.ts—UploadContexthas no setter methods; it's a plain data type- No code path in
UploadSessionorUploadWorkermutates the context after construction
12. Engine Does Not Interpret Intent
The engine stores UploadContext<T> but never branches on its contents.
Enforced by:
UploadEngine.ts—start<T>()passesoptions.contextto session constructor without reading itUploadWorker.ts— never accessessession.contextfor control flow- The generic
<T>parameter means the engine literally cannot know the shape at compile time
13. Event-Driven Communication Only
The engine communicates outward only via emitUploadEvent(). No direct method calls into consumers.
Enforced by:
UploadEvents.ts— singleemitUploadEvent()function is the only outbound channelUploadEngine.ts:201—handleEvent()publishes events; does not call consumer APIsindex.ts— no consumer interfaces or callback registries are exported
14. Listener Boundaries Are Strict
UploadContext (React) subscribes and stores. UploadListener (React) observes and reacts.
Enforced by:
- Architectural convention — these layers live outside
src/lib/internal/UploadEngine/ - The engine has no knowledge of these consumers; it only emits to Signal
- Boundary violations are caught in code review (no compile-time enforcement for external layers)
15. Abort Is Terminal
Aborting an upload is irrecoverable. Aborted uploads never resume.
Enforced by:
UploadStateMachine.ts:58—isTerminalState('aborted')returnstrueUploadStateMachine.ts— no transition exists fromabortedto any other stateUploadWorker.ts:65—requestAbort()aborts the controller;AbortErrorpropagatesUploadSession.ts:133—abort()checksisTerminalStateand no-ops if already terminal
16. Failure Resolves Explicitly
All failures resolve into failed, completion_failed, needs_attention, or aborted. No indeterminate states.
Enforced by:
UploadWorker.ts:72-107—run()catch block routes errors to specific terminal statesUploadSession.ts:122—fail(stage, message)transitions tofailedorcompletion_failedbased on stageUploadStateMachine.ts—isTerminalState()covers all end states;requiresAttention()covers attention state
17. Storage Is Not the Source of Truth
Object storage is a transport layer. Orphaned or duplicate objects are acceptable intermediate states.
Enforced by:
- The engine never queries S3 to verify upload state
UploadPersistence.tsusessessionStorage, not object storage, as the persistence layer- No S3 cleanup or deduplication code exists in the engine
18. Analytics Are Observational
Analytics observe events; they never influence upload behavior.
Enforced by:
- No analytics imports exist in any Upload Engine file
- Events are emitted to Signal bus; analytics subscribes externally
- No conditional logic based on analytics state
19. Predictability Over Throughput
Deterministic behavior is preferred over maximum throughput.
Enforced by:
UploadEngine.ts:25—MAX_PARALLEL_UPLOADS = 5is a hard constant, not configurable per-callUploadWorker.ts:221—PARALLEL_CHUNK_LIMIT = 5is a static readonly, not dynamicUploadQueue.ts— FIFO ordering with no priority scheduling (exceptprioritize()for resume)
20. Infrastructure First
The Upload Engine is infrastructure. Clarity over cleverness, stability over flexibility.
Enforced by:
- 12 focused, single-responsibility source files
- Zero UI framework dependencies
- Pure functions for state machine, retry policy, and chunk math
- Singleton pattern prevents multiple engine instances
Quick Reference
| # | Invariant | Key Enforcement File |
|---|---|---|
| 1 | Single orchestrator | UploadEngine.ts, index.ts |
| 2 | UI independence | All files (zero React imports) |
| 3 | Completion is state | UploadSession.ts, UploadWorker.ts |
| 4 | Explicit state machine | UploadStateMachine.ts |
| 5 | Single source of truth | UploadEngine.ts, UploadSession.ts |
| 6 | No shared mutable state | Per-session instance isolation |
| 7 | Pause/resume first-class | UploadWorker.ts, UploadStateMachine.ts |
| 8 | Persistence guarantees | UploadPersistence.ts, UploadEngine.ts |
| 9 | Upload ≠ domain | index.ts, UploadTypes.ts |
| 10 | Event-driven completion | UploadEvents.ts |
| 11 | Immutable intent metadata | UploadSession.ts, UploadTypes.ts |
| 12 | Engine doesn't interpret intent | Generic <T> parameter |
| 13 | Event-driven only | UploadEvents.ts |
| 14 | Listener boundaries | Architectural convention |
| 15 | Abort is terminal | UploadStateMachine.ts |
| 16 | Failure resolves explicitly | UploadWorker.ts, UploadSession.ts |
| 17 | Storage ≠ truth | No S3 queries in engine |
| 18 | Analytics are observational | No analytics imports |
| 19 | Predictability over throughput | Hard constants |
| 20 | Infrastructure first | Module design |