Future

Prev Next

Future

This document captures work that has been considered and deferred to protect correctness, simplicity, and long-lived invariants. Nothing here is a commitment.

Purpose

The Upload Engine is deliberately conservative. Many ideas are deferred because:

  • the current implementation satisfies all production requirements
  • premature optimization would compromise the invariants in invariants.md
  • migration cost must be justified by concrete need

Current Implementation Gaps

Based on the source code, these are observable areas where the engine is minimal by design:

Area Current State What's Missing
Retry policy Linear backoff 1000 * attempt ms (RetryPolicy.ts:73) No exponential backoff, no jitter, no adaptive strategies
Persistence sessionStorage only (UploadPersistence.ts) No IndexedDB, no cross-tab sync, no crash recovery beyond tab reload
Concurrency Hard constants (MAX_PARALLEL_UPLOADS = 5, PARALLEL_CHUNK_LIMIT = 5) No dynamic tuning based on network conditions
Observability Events emitted to Signal bus No structured metrics, no duration tracking, no retry analytics
Cleanup Engine does not clean up aborted multipart uploads on S3 Orphaned objects accumulate until backend lifecycle rules run
Error granularity isRetryableError() checks status codes and network errors No differentiation between timeout, DNS, TLS, or rate-limit errors

Deferred Capabilities

1. Backend Cleanup and Reconciliation

Gap: Aborted uploads leave partial multipart objects in S3. The engine calls session.abort() but does not issue AbortMultipartUpload to S3.

Potential approach:

  • Add UploadService.abortMultipartUpload(uploadId) static method
  • Call in UploadWorker.run() catch block when abort is detected
  • Make cleanup best-effort (fire-and-forget)

Constraints:

  • Cleanup must never block state transitions
  • Cleanup must be safe to fail silently
  • completed upload objects must never be touched

2. Enhanced Persistence

Gap: sessionStorage is tab-scoped and cleared on tab close. Browser crash = lost in-progress state.

Potential approach:

  • Add IndexedDB adapter behind UploadPersistence interface
  • Swap via internalFlags or config, not constructor change
  • Keep PersistedUploadState shape unchanged

Constraints:

  • Must not disrupt existing sessionStorage persistence
  • Cross-tab dedup would require distributed lock or leader election
  • Persistence format versioning required (see migrations.md)

3. Adaptive Retry Strategies

Gap: RetryPolicy.ts uses linear backoff (1000 * attempt). No jitter, no exponential curve, no per-endpoint configuration.

Potential approach:

// Future: RetryPolicy could accept strategy
type RetryStrategy = 'linear' | 'exponential' | 'exponential-jitter';

Constraints:

  • Default must remain linear for backward compatibility
  • Strategy must not depend on domain context (Invariant #12)
  • Predictability over throughput (Invariant #19)

4. Structured Observability

Gap: No structured metrics. Upload duration, retry counts, and failure rates are not tracked.

Potential approach:

  • Add UPLOAD_METRICS event type to UploadEvent union
  • Emit at completion with { duration, retries, chunksUploaded, bytesTransferred }
  • Keep it observational — never influence engine behavior (Invariant #18)

Constraints:

  • Must be additive to event union (no breaking changes)
  • Analytics consumers subscribe to Signal bus externally
  • Zero performance impact requirement

5. Dynamic Concurrency Tuning

Gap: MAX_PARALLEL_UPLOADS = 5 and PARALLEL_CHUNK_LIMIT = 5 are compile-time constants.

Potential approach:

  • Accept via UploadEngine configuration (not per-upload)
  • Validate bounds at construction time
  • Log effective configuration on first upload

Constraints:

  • UI must not control concurrency (Invariant #19)
  • Changes must not affect in-progress uploads
  • Configuration must be immutable after engine construction

6. Multi-Upload Coordination

Gap: Each upload is fully independent. No batch awareness or dependency ordering.

Potential approach:

  • startBatch(uploads[]) returning BatchId
  • Batch-level events (BATCH_PROGRESS, BATCH_COMPLETED)
  • Per-upload behavior unchanged

Constraints:

  • Uploads must remain isolated by default — coordination is opt-in
  • Batch failure must not cancel successful individual uploads
  • Adds significant complexity — requires strong justification

Explicit Non-Goals

The following are not planned and would require architecture review if ever proposed:

Non-Goal Rationale
UI-driven orchestration Violates Invariant #1 (single orchestrator) and #2 (UI independence)
Synchronous backend cleanup Cleanup must never block upload state transitions
Storage-level deduplication Not a correctness concern; bucket hygiene is separate
Coupling upload success to domain success Violates Invariant #9 (upload ≠ domain)
Server-side upload orchestration Engine runs in browser; server upload is a different system
File preview / thumbnail generation Domain concern, not infrastructure

Evolution Rules

Any future work must:

  1. Preserve all 20 invariants documented in invariants.md
  2. Be additive by default — no breaking changes to public API
  3. Include migration plan if persistence format changes (see migrations.md)
  4. Include tests verifying backward compatibility
  5. Be justified by concrete production need, not speculative improvement