Skip to content

fix(nomadnet): load images that arrive via partial refresh - #99

Open
torlando-tech wants to merge 1 commit into
mainfrom
feat/nomadnet-inline-images-cumulative
Open

torlando-tech wants to merge 1 commit into
mainfrom
feat/nomadnet-inline-images-cumulative

Conversation

@torlando-tech

Copy link
Copy Markdown
Owner

Follow-up to #98 (merged). Physical testing of the inline-images feature on a cycling partial-region page found that images inside a dynamic (partial) region never load in Pyxis: the compact-page merge adds their records, but the image loader was configured only on full page load, so region images stay alt-text placeholders forever. The official NomadNet client renders them because its image updater rescans page images after every partial update.

Fix: ImageLoader::reconfigure rebuilds the entry list from the merged page, keyed by (image_index, cache_key):

  • unchanged (index, url) pairs keep state verbatim — LOADED stays loaded, no refetch
  • replaced urls at the same index are re-admitted fresh (no stale pixels)
  • new indices admitted under the same policy gate as the full-page configure
  • an in-flight REQUESTING entry whose record was replaced in flight is reported orphaned so the caller releases the outstanding receipt (seal-then-release) before the next request

UIManager::nomad_reconfigure_images_after_partial mirrors the full-page configure (policy/loopback/RTT/EDR), runs after each applied fragment, and surfaces manual-mode pending state.

Verification: 6 new loader scenarios (shrink / grow / in-place replace / in-flight orphan / in-flight preserved / manual / never); native suite 311 passed; tdeck + tdeck-release build; release audit pass (pins unchanged); x86 real-peer flow 11/11.

The image loader was configured only on full page load, so images inside a
dynamic (partial) region never fetched: the compact-page merge added their
records, but the loader never knew. Physical test on the cycling partial
page showed region images stuck as alt-text placeholders while the
official client rendered them (its image updater rescans page images
after every partial update).

Add ImageLoader::reconfigure: rebuild the entry list from the merged
page, keyed by (image_index, cache_key). Unchanged (index,url) pairs keep
their state verbatim (LOADED stays loaded, no refetch); replaced urls at
the same index are re-admitted fresh; new indices are admitted under the
policy gate; dropped indices are removed. An in-flight REQUESTING entry
whose record was replaced in flight is reported orphaned so the caller
releases the outstanding receipt before the next request.

UIManager::nomad_reconfigure_images_after_partial mirrors the full-page
configure (policy/loopback/RTT/EDR), runs after a fragment is applied,
and releases an orphaned in-flight request (seal-then-release ordering).
Manual policy: new region images wait for the user trigger; loaded ones
stay loaded.

Tests: six reconfigure scenarios (shrink, grow, in-place replace,
in-flight orphan, in-flight preserved, manual, never).

Co-Authored-By: Hermes <noreply@nousresearch.com>
@greptile-apps

greptile-apps Bot commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 3/5

The PR is not ready to merge because partial refreshes can strand both previously displayed images and an in-flight image request.

Fix All in Claude CodeFindings

  1. P1 Loaded images lose their pixels ▶
  2. P1 Allocation failure strands image requests ▶
Fix with agent prompt
### Issue 1
lib/tdeck_ui/UI/LXMF/NomadNetImageLoader.cpp:121-125
When a partial refresh adds an image after four images are already displayed, storing the new image evicts one of the screen’s four decoded pixel slots. This branch still preserves the evicted image’s `LOADED` state, so the loader never fetches it again and the unchanged part of the page shows a placeholder. The loader needs to account for decoded-slot eviction when preserving loaded state.

### Issue 2
lib/tdeck_ui/UI/LXMF/NomadNetImageLoader.cpp:169-172
If allocation fails while rebuilding the entries, this returns `false` and retains the old loader state. The caller treats `false` as an orphaned request and releases its receipt, even if the in-flight image is unchanged. That entry remains `REQUESTING` without a request, so later polls will not fetch it or advance past it. Allocation failure needs a result distinct from an orphaned request, or the retained entry must be reconciled when its receipt is released.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

The PR rebuilds NomadNet image-loader entries after an applied partial refresh, preserving unchanged entries and admitting new or replaced image records. It also releases orphaned image requests and adds loader scenarios for refresh and policy behavior.

  • New region images can load, but admitting them can evict pixels for images whose loader state remains LOADED.
  • Allocation failure can leave a retained request entry stuck after its receipt is released.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Partial fragment applied] --> B[Rebuild image entries]
  B --> C{Same index and cache key?}
  C -->|Yes| D[Preserve loader state]
  C -->|No| E[Admit under policy gate]
  E --> F{Old request orphaned?}
  F -->|Yes| G[Seal mailbox and release receipt]
  F -->|No| H[Poll pending images]
  G --> H
Loading

Reviews (1) · Last reviewed commit: "fix(nomadnet): load images that arrive v..."

Comment on lines +121 to +125
if (prior && prior->data.cache_key == entry.cache_key) {
// Same image at the same index: preserve state verbatim.
next.data = std::move(entry);
next.state = prior->state;
next.terminal_failure = prior->terminal_failure;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Loaded images lose their pixels When a partial refresh adds an image after four images are already displayed, storing the new image evicts one of the screen’s four decoded pixel slots. This branch still preserves the evicted image’s LOADED state, so the loader never fetches it again and the unchanged part of the page shows a placeholder. The loader needs to account for decoded-slot eviction when preserving loaded state.

Knowledge Base Used: NomadNet browser

Prompt To Fix With AI
This is a comment left during a code review.
Path: lib/tdeck_ui/UI/LXMF/NomadNetImageLoader.cpp
Line: 121-125

Comment:
**Loaded images lose their pixels** When a partial refresh adds an image after four images are already displayed, storing the new image evicts one of the screen’s four decoded pixel slots. This branch still preserves the evicted image’s `LOADED` state, so the loader never fetches it again and the unchanged part of the page shows a placeholder. The loader needs to account for decoded-slot eviction when preserving loaded state.

**Knowledge Base Used:** [NomadNet browser](https://app.greptile.com/torlando-tech/-/custom-context/knowledge-base/torlando-tech/pyxis/-/docs/nomadnet-browser.md)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Claude Code

Comment on lines +169 to +172
} catch (const std::bad_alloc&) {
// Leave the previous configuration intact on allocation failure:
// the page keeps whatever loader state it had (best-effort).
return false;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Allocation failure strands image requests If allocation fails while rebuilding the entries, this returns false and retains the old loader state. The caller treats false as an orphaned request and releases its receipt, even if the in-flight image is unchanged. That entry remains REQUESTING without a request, so later polls will not fetch it or advance past it. Allocation failure needs a result distinct from an orphaned request, or the retained entry must be reconciled when its receipt is released.

Prompt To Fix With AI
This is a comment left during a code review.
Path: lib/tdeck_ui/UI/LXMF/NomadNetImageLoader.cpp
Line: 169-172

Comment:
**Allocation failure strands image requests** If allocation fails while rebuilding the entries, this returns `false` and retains the old loader state. The caller treats `false` as an orphaned request and releases its receipt, even if the in-flight image is unchanged. That entry remains `REQUESTING` without a request, so later polls will not fetch it or advance past it. Allocation failure needs a result distinct from an orphaned request, or the retained entry must be reconciled when its receipt is released.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Claude Code

This branch has not been deployed

No deployments
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