Skip to content

fix(desktop): memoize mission inbox snapshots on inputs, not the wall clock - #138

Merged
oscarlehuu merged 2 commits into
mainfrom
devin/1786408626-fix-mission-inbox-memo
Aug 11, 2026
Merged

fix(desktop): memoize mission inbox snapshots on inputs, not the wall clock#138
oscarlehuu merged 2 commits into
mainfrom
devin/1786408626-fix-mission-inbox-memo

Conversation

@devin-ai-integration

Copy link
Copy Markdown

Summary

Root cause. deriveMissionInboxSections derives const now = input.now ?? Date.now() and then folds that now into its module-level memo key:

const key = JSON.stringify({ /* …inputs… */, now });
if (key === lastKey) return lastSections;

When the caller supplies no now — which the only caller, useMissionInboxSections, never does — each invocation samples the wall clock independently. Two calls with the same input object therefore produce different keys whenever they straddle a millisecond tick, the memo misses, and a fresh object is returned. That is exactly what missionInbox.test.mjs:654 catches: it calls the function twice back-to-back and asserts reference equality. The failure rate is simply derive duration / 1ms. Nothing in the key is order- or hash-dependent; the clock is the only nondeterministic component.

Discriminating evidence (2000-iteration probe through the repo loader on unmodified main): 8/2000 iterations returned non-reference-equal snapshots, and 8 of those 8 coincided with the two Date.now() samples differing, while all 1992 reference-equal iterations had identical samples.

Fix. The memo key is now a pure function of caller-provided inputs: an explicitly supplied input.now stays part of the key, the implicit Date.now() fallback does not.

-    now,
+    now: input.now,

Identical inputs ⇒ cache hit ⇒ identical object, always — which is what a getSnapshot-shaped selector must guarantee. A caller that wants clock-driven recomputation passes now explicitly, and a new test pins that direction of the contract too.

Accepted consequence, recorded as D-039: without an explicit clock, row age values are fixed at snapshot time and refresh only when a real input changes. This is not a behavior regression — the sole caller passes no clock and the home surface has no ticker, so ages already only updated when a store changed.

The flaky test itself is untouched: no skip, no retry, no tolerance, no weakened assertion.

DECISIONS.md numbering: took D-039 per the coordination note (D-028 through D-038 are allocated to in-flight PRs #120, #124, #127, #129, #134, #128 and reserved 037/038). No STATE.md change — this fixes existing shipped behavior rather than changing the shipped slice.

Related issue

Fixes #135.

Testing

Narrowed named test, run through the repo harness with a validity guard (a run that matches 0 tests is counted INVALID, not a pass, so no tally is vacuous):

pnpm --filter buzz exec node --import ./test-loader.mjs --experimental-strip-types \
  --test --test-name-pattern='same inputs return a reference-stable snapshot' \
  src/features/home/lib/missionInbox.test.mjs
Branch Runs Pass Fail
unmodified origin/main @ 35af74019 40 37 3 (iterations 23, 27, 31)
this branch 50 50 0

Representative failure on main:

✖ same inputs return a reference-stable snapshot (2.281741ms)
  AssertionError [ERR_ASSERTION]: Values have same structure but are not reference-equal:
  { needsYou: [], readyToReview: [], working: [] }
      at .../missionInbox.test.mjs:665:10

Full gates on this branch, all clean:

  • pnpm --filter buzz testℹ pass 5046, ℹ fail 0, ℹ skipped 1
  • pnpm --filter buzz check — Biome, 2195 files, no fixes needed
  • pnpm --filter buzz typecheck — clean

No UI change, so no screenshots.

Link to Devin session: https://app.devin.ai/sessions/c247a65930ba49ed8471a10d38931037
Requested by: @oscarlehuu

devin-ai-integration Bot and others added 2 commits August 11, 2026 00:40
Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Oscar Le <oscar.lehuu@gmail.com>
Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Oscar Le <oscar.lehuu@gmail.com>
@oscarlehuu oscarlehuu self-assigned this Aug 11, 2026
@devin-ai-integration

Copy link
Copy Markdown
Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@devin-ai-integration

Copy link
Copy Markdown
Author

CI status: required lanes green, red lanes are preexisting

Green here: Desktop Fast (job 93643105792) and the required NuncioCrew Gate (job 93644384319) — the two lanes #135 was breaking — plus macOS ARM Package, Desktop Smoke E2E (2), CI Policy, Desktop Release Candidate.

Red/cancelled, all preexisting on main and not touched by this change:

Lane This PR Same lane on main
Desktop Smoke E2E (1) job 93643105814 run 31362178966, job 93373095535 — same channel activity hover preview › … failures
Desktop Smoke E2E (3) job 93643105804 run 31362178966, job 93373095539 — same inbox/messaging failures
Desktop Smoke E2E (4) job 93643105819, cancelled at the 30m timeout run 31362178966, job 93373095513, cancelled the same way — #109

channels.spec.ts:500 › channel question card accepts an answer is #110.

One PR-side smoke failure was in the feature area this PR touches, so it got its own check rather than a hand-wave: tests/e2e/mission-inbox.spec.tspage.evaluate: Execution context was destroyed… at helpers/animations.ts:22. The same spec (mission-inbox.spec.ts:19 › ingests a live 46040 request, falls back to its channel, and resolves it) already fails and is classified flaky on main run 31325507788, job 93275126338, passing on retry there. It is a harness navigation race, not a consequence of the memo change — the memoization change is exercised by the 50/50 unit-level loop in the description.

gh run rerun --failed on run 31446933581 is rejected for this app token (Resource not accessible by integration), so no fresh rerun of the smoke shards is attached.

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.

Flaky merge-gating test: missionInbox 'reference-stable snapshot' fails intermittently on main (fails Desktop Fast + NuncioCrew Gate)

1 participant