fix(orchestration): keep the first staleSince while a source keeps failing - #12544
pacocartones wants to merge 2 commits into
Conversation
…iling `buildSourceStatuses` stamped every failed source with the current poll's `nowIso`, so with the `sourceStale` message live the node showed "stale since <last poll>" instead of the first error, and `snapshotContentKey` changed every tick for as long as a source was down. Carry the previous `staleSince` forward through a pure `carryStaleSince(prev, next)` applied in the functional `setStatuses` update; a recovered source has no `staleSince`, so the next failure is stamped fresh. Refs diegosouzapw#12392
|
Closing as subsumed. #12983 (orchestration canvas fase 3) landed on It is fed through the functional updater form for the same reason you used one — no stale closure over I checked whether your test was worth carrying over and it is already covered three times on the tip: "keeps staleSince pinned to the first failure across consecutive failing polls", "stamps a fresh staleSince when a source fails again after recovering", and "keeps snapshot referential identity across polls while a source keeps failing with an unchanged payload". Both halves of your case land inside those, so there is nothing left to port. The rest of your batch merged today — 17 of them. Thanks for the |
Summary
buildSourceStatuses(src/app/(dashboard)/dashboard/orchestration/hooks/useOrchestrationSnapshot.ts:63-90) stamps every failed source with the current poll'snowIso(lines 76, 79, 87), and the poll loop replaced the whole list withsetStatuses(next). With thesourceStalemessage now live,SourceNode(nodes/SourceNode.tsx:24-28) therefore read "stale since " instead of the first error, and becausesnapshotContentKeyserialisess.sources, the key changed on every 5s/30s tick for as long as a source was down — re-minting the node/edge arrays theReact.memogate exists to protect.staleSinceavança a cada poll"). Fix: a purecarryStaleSince(prev, next)helper (line 99) copies the previousstaleSinceonto a source that was already failing, applied through the functional updatesetStatuses((prev) => carryStaleSince(prev, next))(line 152). A source that recovers is pushed as{ ok: true }with nostaleSince, so the next failure is stamped fresh; a first failure keeps this poll'snowIso.buildSourceStatuses,mergeSnapshotand the conductorofflinebranch are untouched.mergeSnapshot, a11y,noMatches, particle budget, drawer error banner,toggleCsv) — each is a separate surface and the issue stays open.Related Issues
Validation
./node_modules/.bin/vitest run --config vitest.config.ts tests/unit/ui/useOrchestrationSnapshot.test.tsx8/8;tests/unit/ui/orchestration*+ the hook test 89/89 (7 files);node scripts/check/check-complexity-ratchets.mjs --base-ref origin/release/v3.8.51OK (0 violations, cognitive 0);npm run check:changelog-integrityOK;npm run typecheck:coreexit 0npm run lintrelease/v3.8.51(on top of feat(dashboard): orchestration canvas fase 2 — repeat action + A2A memory hits (2.6/2.7) #12508 / chore(quality): tighten the CodeQL ratchet baseline from 11 to 6 #12530); focused checks rerun afterwardeslint on the two touched files exits 0 (also run by the lint-staged pre-commit hook).
Tests Added Or Updated
tests/unit/ui/useOrchestrationSnapshot.test.tsx— new case "keeps the first staleSince while a source keeps failing and clears it once it recovers (feat: orchestration canvas polish (fase 2 PR-A final-review minors) #12392)": ok → fail → fail → ok with fake timers. Asserts nostaleSinceon the healthy poll, a string on the first failure, the SAME value on the next failing poll 5s later (base fails here:expected '…:18.927Z' to be '…:13.927Z'), snapshot referential identity preserved across the two failing polls, andstaleSincecleared on recovery. Red on the base (1 fail / 7 pass), green with the change (8/8). The seven existing cases are unchanged.Coverage Notes
src/app/(dashboard)/dashboard/orchestration/hooks/useOrchestrationSnapshot.ts:carryStaleSinceis exercised end-to-end through the hook in all three branches (first failure → keep own stamp; repeated failure → carry; recovery → drop) by the new case, plus the existing "failed source keeps the last good data" case.Reviewer Notes
staleSincevalue while a source stays down;ok,errorandofflineare still refreshed every poll.errortext changing between polls will still bump the content key, which is intended (it is user-visible).changelog.d/fixes/PENDING-orchestration-keep-first-stale-since.md— renamePENDINGto the PR number after opening.