Skip to content

[P1-22] Harden and test the asynchronous image pipeline #27

Description

@phranck

Problem

Image tests cover conversion but not the asynchronous view lifecycle. Current risks include:

  • URL loading uses a semaphore and nonisolated(unsafe) result state in Sources/TUIkitImage/ImageLoader.swift:248-279.
  • URLImageCache.shared is global (ImageLoader.swift:194-201).
  • _ImageCore constructs its concrete loader and writes source/phase boxes during rendering (Sources/TUIkit/Views/_ImageCore.swift:65-118).
  • Phase updates can arrive outside the correct actor, repeat invalidation, or let an old response overwrite a newer source.
  • Cancellation, status/MIME validation, byte/pixel limits, timeout, cache behavior, and disappear are not covered end to end.

Proposed solution

  • Inject a per-app loader, cache, clock, and transport; keep live networking out of tests.
  • Model request state on the owning actor and cancel on source/identity change, disappear, and shutdown.
  • Deduplicate identical in-flight requests and prevent stale completion from committing.
  • Validate HTTP status, MIME, byte count, dimensions, pixel count, timeout, redirects, and decode/decompression limits.
  • Build public AsyncImage phase/API behavior on this pipeline in the content API issue.

Acceptance criteria

  • Deterministic tests cover cache hit/miss, deduplication, source change, cancellation, timeout, redirect policy, status/MIME rejection, size/decode errors, disappear, and shutdown.
  • A stale response can never replace a newer view phase.
  • Two app runtimes share neither cache nor in-flight requests unless explicitly configured.
  • Rendering does not mutate image phase merely by reading the same source.
  • No semaphore or unsafe cross-actor result variable remains in async loading.
  • Swift 6.0 macOS/Linux build, tests, lint, and DocC are warning-free.

Dependencies

Depends on per-app runtime #8, async loop #9, stable lifecycle identity #10, and pure Swift decoder #16.

Parallelization

After those contracts settle, transport/cache work can proceed beside content API work, with _ImageCore lifecycle integration owned here.

Commit structure

  • Split this issue into small, thematic, independently revertible commits wherever the work can remain coherent.
  • Every commit must build and keep its applicable tests/gates green. Do not commit an intentionally failing regression test; use local/known-issue characterization or land the test with the smallest fix.
  • Keep characterization/fixtures, mechanical renames or moves, semantic changes, and documentation/migration updates separate when each step remains green.
  • The issue boundary is not a commit boundary; multiple commits are expected for independently reversible changes.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingpriority: highHigh-impact correctness, compatibility, or SDK completeness work

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions