Skip to content

Fix: Derive the image placeholder instead of mutating state in traversal#63

Merged
phranck merged 2 commits into
mainfrom
issue/27-image-placeholder-derivation
Jul 22, 2026
Merged

Fix: Derive the image placeholder instead of mutating state in traversal#63
phranck merged 2 commits into
mainfrom
issue/27-image-placeholder-derivation

Conversation

@phranck

@phranck phranck commented Jul 21, 2026

Copy link
Copy Markdown
Owner

Summary

  • _ImageCore no longer mutates its phase/lastSource state boxes while rendering. The placeholder for a changed source is derived from lastSource != source, so it still appears in the same frame as the source change — without any state write inside the traversal window.
  • The mounted loading task is now the only writer of both boxes: it commits the phase first, then the source, and skips the commit entirely when cancelled. A stale load can therefore never pair with a newer source (renders in between derive the placeholder).
  • Root cause surfaced by [P0-08d] Document the phase model and diagnose body side effects #58: the previous resetLoadingPhaseIfNeeded wrote lastSourceBox on every frame, so every frame containing an image emitted a body-side-effect RuntimeDiagnostic (plus a superfluous invalidation). Rendering an image is now diagnostic-free.
  • New ImageRenderPhaseTests cover both contracts end-to-end via FrameHarness (which gained an injectable TUIContext for deterministic loaders); mountLoadingTask now reads its dependencies from the render context (SwiftLint function_parameter_count).

Refs #27 — delivers the "Rendering does not mutate image phase merely by reading the same source" acceptance criterion; the remaining transport/validation/dedup work stays in #27.

Test plan

  • ImageRenderPhaseTests: RED verified against the old behavior (diagnostic on every frame), GREEN after the fix
  • Placeholder still shows in the same frame as a source change (asserted against the frame's terminal diff)
  • ./scripts/test-linux.sh: full warning-fatal gate green on macOS and Linux (1317 tests, 1 expected known issue for [P0-09] Preserve subtree liveness across EquatableView cache hits #14)

phranck added 2 commits July 22, 2026 01:40
- _ImageCore no longer writes its phase/lastSource state boxes while
  rendering; the placeholder for a changed source is derived from
  lastSource != source, so it still shows in the same frame
- The mounted loading task is now the only writer: it commits phase
  first, then lastSource, and skips the commit when cancelled, so a
  stale load can never pair with a newer source
- Since #58 every image frame emitted a body-side-effect
  RuntimeDiagnostic (unconditional lastSource write); rendering is now
  diagnostic-free
- Add ImageRenderPhaseTests and an injectable TUIContext on FrameHarness
- mountLoadingTask reads lifecycle, loader, cache, timeout, and pixel
  limit from context.environment instead of taking nine parameters
  (SwiftLint function_parameter_count)
@phranck
phranck merged commit 21f140a into main Jul 22, 2026
6 checks passed
@phranck
phranck deleted the issue/27-image-placeholder-derivation branch July 22, 2026 00:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant