Return legs from /download/ to /: Fix now lands on the missing field, and a bfcache miss keeps the résumé
@s-annam is already working on this.
Since Oct 7, 2026.
Assessment
This issue has not been assessed yet.
Description
Part of epic #1179. Blocked by #1181 (the /download/ page).
Problem
Once Download is its own page at /download/ (#1181), every route back to the editor on / is a real navigation, and two of them need more than a link:
Fix nowlands the user on the wrong spot. The soft gate'sFix nowused to close the dialog and callfixFirstGap(missing)on the same page (ExportGateBody.tsx,ExportDialog.tsx:200-204). That scrolled to the first missing field and focused it. From/download/it can only navigate to/, so the user arrives at the top of the résumé with no idea which field the gate meant.- The return leg can lose an unedited parse. Going back to
/is usually a bfcache restore with React state, and so edits, intact (useAutoRestoreResume.tsdocblock, #783). On a bfcache miss (Chrome evicts freely, and/holds an open IndexedDB connection),/cold-mounts and auto-restores the newest library record. A résumé the user never edited was never autosaved (#824), so they land on the drop zone, or on a different résumé, after merely looking at Download./jobs/has the same exposure today, but Download is reached far more often.
Change
Fix now → / focused on the first gap
- Add a one-shot
sessionStoragehandoff,ocv_fix_gap(mirrortailor-handoff.ts's shape and itsfingerprintParseguard), carrying the gate's first missing item and the résumé fingerprint.Fix nowwrites it, then navigates to/(withhistory.back()when the referrer is our/, so the bfcache entry is reused rather than a new one pushed). /consumes it on mount and onpageshowwithpersisted === true. The bfcache leg never remounts, which is exactly the trap #783 documents for the tailor handoff. If the fingerprint matches the parse on the page, call the existingfixFirstGap(...). Otherwise drop it silently.- It must not race
useAutoRestoreResume. Like the pending tailor handoff, a pending fix-gap handoff makes auto-restore defer to it, using a non-destructive peek (hasPending…), never a consume.
Back to résumé and the bfcache-miss fallback
Back to résumédoeshistory.back()when the previous entry is our/, so bfcache keeps the edits, and otherwiselocation.assign("/").- On a cold mount of
/with no parse in memory, the download handoff (#1180) is a restore source. Ifocv_download_handoffholds a résumé whosejourneyKeymatches no library record that auto-restore would pick,/restores that one. It is the résumé the user was just looking at, already sitting in tab-scoped storage. Restore it as a read-only view of the applied result, or as an authoring-lane load, whichever needs no edit replay. If neither is feasible without an edit-layer replay, stop at documenting the limitation inuseAutoRestoreResume's docblock, file the follow-up, and say so in the PR.
Acceptance criteria
- From
/download/,Fix nowwith a missing email lands on/with the email field focused. This holds on a bfcache restore (e2e:page.goBack()) and on a cold load (e2e: open/with the handoff seeded). - A fix-gap handoff whose fingerprint does not match the page's parse is dropped without focusing anything (unit test).
- With a fix-gap handoff pending, auto-restore does not consume or clobber it (unit test, mirroring the tailor-handoff guard).
-
Back to résuméreuses the history entry when the user came from/, so going Download → Back → Download → Back does not grow history. - Simulated bfcache miss (cold
/withocv_download_handoffpresent, no library record for it): the user sees the résumé they were downloading, not the drop zone, or the documented-limitation path is taken with a filed follow-up.
- Dominant language
- TypeScript
- Stars
- 11
- Forks
- 4
- PR merge metrics
- No merged PRs in 30d
Getting set up
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from offlinecv/OfflineCV
-
fix(heuristics): unit number before a Saint-named city drops "St." from the locationPossibly taken @gaal-agent claimed this 12 days ago. Openbug gaal ux:parsing
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
-
Migrate Gaal implement/review/revise to the local gaal watch; keep mechanical workflows on ActionsOpenarchitecture chore github_actions needs-human ready-for-agent
Difficulty 5/5 Over a week Newbie friendliness 8/100
-
Parser: achievement year lost on re-import when '· YYYY' wrapped to its own linePossibly taken @gaal-agent claimed this 7 days ago. Openbug gaal ready-for-agent ux:parsing
Difficulty 3/5 1-2 days Newbie friendliness 25/100
-
Export: auto-bolded metric bullets extract one word per line in stream-order parsers (pypdf/Drive)Possibly taken @gaal-agent claimed this 7 days ago. Openbatch:export-standards bug gaal ready-for-agent ux:edit-export
Difficulty 3/5 1-2 days Newbie friendliness 25/100
-
bug duplicate improvement
Difficulty 3/5 Half a day Newbie friendliness 66/100
All issues in offlinecv/OfflineCV
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
logancyang/obsidian-copilot#3753 ·
Maintainers usually reply within 1 day
-
area: presentation severity: important
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
voithos-labs/aragonite#763 ·
Maintainers usually reply within 2 days
-
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
diegosouzapw/OmniRoute#17386 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 Half a day Newbie friendliness 72/100
super-productivity/super-productivity#10982 · 1 comment ·
Maintainers usually reply within 1 day