Skip to content

VI-5068 Keep re-checking an embed source until its flow has something to show - #24

Merged
helgehoi merged 1 commit into
mainfrom
VI-5068-embed-recheck-until-ready
Aug 26, 2026
Merged

helgehoi merged 1 commit into
mainfrom
VI-5068-embed-recheck-until-ready

Conversation

@helgehoi

Copy link
Copy Markdown
Collaborator

Ticket

VI-5068 — [tamstool] Upgrade TAMS Store Browser to TAMS 8.2

Follows #23, which made a live source openable at all. This makes it become openable while you watch.

The bug

With /#/embed open, a recording that starts never grows an Open button. Reloading the page produces one immediately. Reported against an 8.2 store; pre-8.2 stores transition correctly.

Why

Every source was examined once and the verdict cached forever:

if (isGrowing) {
  growingRef.current.set(source.id, flow.id);
} else {
  closedRef.current.add(source.id);   // "Permanent cache for closed sources — never re-fetched"
  growingRef.current.delete(source.id);
}

closedRef was filled by not growing, which is not the same as finished. A store may create the flow when the recording is scheduled and only fill it once the ingest starts, so the first look — taken before any segment exists, with the flow reading awaiting_content or simply empty — permanently decided that the source had nothing to offer. Nothing re-examines a cached source, so the row stays without a button until the cache dies with the page. That is exactly the reload asymmetry: a reload starts with an empty cache and looks again at a moment when segments do exist.

This is 8.2-shaped because 8.2 gives the flow a status from creation, so the flow is visible and classifiable before it holds anything. Where a store instead has no flow at all until the ingest starts, the first look hits if (!flow) return, which never cached anything — the source stayed under review and the transition worked.

The escape hatch added in #20 was meant to cover this, and misses the case it was written for:

liveSourceIds.forEach((id) => closedRef.current.delete(id));

liveSourceIds comes from useIngestingFlows, i.e. the id of the source the flow hangs off. For a multi-source recording that is the video child, while the row on display is the parent collection — so the delete finds nothing and the parent stays cached.

The fix

Cache on settled, not on not-growing:

const hasSettled = (flow, hasSegments) =>
  getFlowStatus(flow) === FLOW_STATUS.CLOSED_COMPLETE || hasSegments;

Nothing further can change the row once the flow is closed, or once it already carries media. awaiting_content, ingesting, and "empty so far" all stay under review, so the existing 5s sources poll re-examines them and the button appears by itself. closedRef is renamed settledRef to say so.

The escape hatch now also matches collection members, so an ingesting video child re-opens the parent row that displays it.

"Loading..." is held to sources with nothing on screen yet — otherwise re-checking a permanently empty flow every 5s would blink it forever.

What this does not change

A flow that never receives a segment is re-checked every 5s for as long as the embed is open. That is two requests per such source per poll. It is the price of not guessing, and it stops as soon as the flow closes.

Testing

Not reproduced against a live store — I have no ingesting 8.2 endpoint, so this is a code-level diagnosis of an asymmetry the reporter observed (8.2 store fails, pre-8.2 store transitions, reload always fixes it). The fix is deliberately robust to each variant of the same trap rather than to one guessed sequence: no flow yet, flow present but empty, flow awaiting_content, and the child/parent id mismatch all now stay under review. Worth confirming on the store that first showed it.

🤖 Generated with Claude Code

A recording that starts while /embed is open never grew an Open button; a
reload produced one immediately. The row was examined once, too early, and
the verdict was cached forever: any flow that was not growing went into the
closed cache and was never fetched again. An empty flow is not a finished one
though -- a store may create the flow when the recording is scheduled and
fill it only once the ingest starts -- so the first look, taken before any
segment exists, permanently decided that the source had nothing to offer.

Cache on settled instead of on not-growing. Settled means nothing further can
change the row: the flow is closed, or it already carries media. Awaiting
content, ingesting, or simply empty so far all stay under review, so the 5s
sources poll re-examines them and the button appears on its own.

The escape hatch that re-opens an ingesting source also missed the case it
was written for: useIngestingFlows reports the source the flow hangs off,
which for a multi-source recording is the video child, while the row on
display is the parent collection. Collection members are now matched too.

"Loading..." is held to sources with nothing on screen yet, so re-checking an
empty flow every 5s does not blink it forever.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@helgehoi
helgehoi merged commit 96ba867 into main Aug 26, 2026
1 check passed
@helgehoi
helgehoi deleted the VI-5068-embed-recheck-until-ready branch August 27, 2026 00:41
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