diff --git a/docs/ui-modernisation/visual-correction/MAIL_ARTICLE_SELECTOR_FAILURE.json b/docs/ui-modernisation/visual-correction/MAIL_ARTICLE_SELECTOR_FAILURE.json
new file mode 100644
index 00000000..8964b334
--- /dev/null
+++ b/docs/ui-modernisation/visual-correction/MAIL_ARTICLE_SELECTOR_FAILURE.json
@@ -0,0 +1 @@
+{"numFailedTestSuites":1,"numFailedTests":2,"numPassedTestSuites":0,"numPassedTests":35,"numPendingTestSuites":0,"numPendingTests":0,"numRuntimeErrorTestSuites":0,"numTodoTests":0,"numTotalTestSuites":1,"numTotalTests":37,"openHandles":[],"snapshot":{"added":0,"didUpdate":false,"failure":false,"filesAdded":0,"filesRemoved":0,"filesRemovedList":[],"filesUnmatched":0,"filesUpdated":0,"matched":0,"total":0,"unchecked":0,"uncheckedKeysByFile":[],"unmatched":0,"updated":0},"startTime":1793773297530,"success":false,"testResults":[{"assertionResults":[{"ancestorTitles":["CorrespondenceInboxPage"],"duration":312,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage en inbox filters and messages support request-free keyboard navigation","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"startAt":1793773301547,"status":"passed","title":"en inbox filters and messages support request-free keyboard navigation"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":176,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage nb inbox filters and messages support request-free keyboard navigation","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"startAt":1793773301860,"status":"passed","title":"nb inbox filters and messages support request-free keyboard navigation"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":397,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage [P7-11 inbox] resumed draft fallback metadata follows locale without mutating stored prose or refetching","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"startAt":1793773302036,"status":"passed","title":"[P7-11 inbox] resumed draft fallback metadata follows locale without mutating stored prose or refetching"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":437,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage renders correspondence inbox items and reloads with filters","invocations":1,"location":null,"numPassingAsserts":11,"retryReasons":[],"startAt":1793773302434,"status":"passed","title":"renders correspondence inbox items and reloads with filters"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":157,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage keeps saved correspondence visible when provider status is unavailable","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"startAt":1793773302871,"status":"passed","title":"keeps saved correspondence visible when provider status is unavailable"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":250,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage opens provider-backed plain-text message detail in the hub","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"startAt":1793773303028,"status":"passed","title":"opens provider-backed plain-text message detail in the hub"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":216,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage navigates beyond the first correspondence page","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"startAt":1793773303278,"status":"passed","title":"navigates beyond the first correspondence page"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":295,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage unlinks a Gmail thread only after confirmation and returns it to review","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"startAt":1793773303495,"status":"passed","title":"unlinks a Gmail thread only after confirmation and returns it to review"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":294,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage falls back to the saved copy when provider detail is unavailable","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"startAt":1793773303790,"status":"passed","title":"falls back to the saved copy when provider detail is unavailable"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":1152,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage keeps replies editable and requires final send confirmation","invocations":1,"location":null,"numPassingAsserts":14,"retryReasons":[],"startAt":1793773304084,"status":"passed","title":"keeps replies editable and requires final send confirmation"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":437,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage saves an incomplete reply with its server delivery identity","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"startAt":1793773305236,"status":"passed","title":"saves an incomplete reply with its server delivery identity"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":424,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage resumes a saved draft and surfaces revision conflicts without overwriting it","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"startAt":1793773305673,"status":"passed","title":"resumes a saved draft and surfaces revision conflicts without overwriting it"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":647,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage persists a new delivery identity only after a definitive failed attempt","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"startAt":1793773306097,"status":"passed","title":"persists a new delivery identity only after a definitive failed attempt"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":665,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage starts a new-message draft only from an owned job and send-capable provider choice","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"startAt":1793773306744,"status":"passed","title":"starts a new-message draft only from an owned job and send-capable provider choice"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":650,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage searches the complete server-side job choice set while composing","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"startAt":1793773307410,"status":"passed","title":"searches the complete server-side job choice set while composing"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":727,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage does not offer retry when delivery is uncertain","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"startAt":1793773308060,"status":"passed","title":"does not offer retry when delivery is uncertain"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":243,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage uses one hub for linked messages and recruitment suggestions","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"startAt":1793773308787,"status":"passed","title":"uses one hub for linked messages and recruitment suggestions"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":113,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage localizes inbox controls while preserving correspondence content","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"startAt":1793773309030,"status":"passed","title":"localizes inbox controls while preserving correspondence content"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":108,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage legacy Gmail review route redirects into the consolidated hub filter","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"startAt":1793773309143,"status":"passed","title":"legacy Gmail review route redirects into the consolidated hub filter"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":202,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage failed inbox reads retain a current-language error and recover with one explicit GET-only Retry","invocations":1,"location":null,"numPassingAsserts":13,"retryReasons":[],"startAt":1793773309251,"status":"passed","title":"failed inbox reads retain a current-language error and recover with one explicit GET-only Retry"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":222,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage a late old page cannot overwrite the latest query and page-one inbox snapshot","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"startAt":1793773309453,"status":"passed","title":"a late old page cannot overwrite the latest query and page-one inbox snapshot"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":168,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage message Retry replays the captured owned detail read without hiding it and localizes saved-copy fallback","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"startAt":1793773309675,"status":"passed","title":"message Retry replays the captured owned detail read without hiding it and localizes saved-copy fallback"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":277,"failing":false,"failureDetails":[{}],"failureMessages":["TypeError: Expected container to be an Element, a Document or a DocumentFragment but got null.\n at checkContainerType (C:\\Users\\Connor\\.codex\\worktrees\\direct-roadmap-integration\\Job tracker\\job-tracker-ui\\node_modules\\@testing-library\\dom\\dist\\helpers.js:61:11)\n at queryAllByRole (C:\\Users\\Connor\\.codex\\worktrees\\direct-roadmap-integration\\Job tracker\\job-tracker-ui\\node_modules\\@testing-library\\dom\\dist\\queries\\role.js:34:35)\n at C:\\Users\\Connor\\.codex\\worktrees\\direct-roadmap-integration\\Job tracker\\job-tracker-ui\\node_modules\\@testing-library\\dom\\dist\\query-helpers.js:74:17\n at C:\\Users\\Connor\\.codex\\worktrees\\direct-roadmap-integration\\Job tracker\\job-tracker-ui\\node_modules\\@testing-library\\dom\\dist\\query-helpers.js:52:17\n at C:\\Users\\Connor\\.codex\\worktrees\\direct-roadmap-integration\\Job tracker\\job-tracker-ui\\node_modules\\@testing-library\\dom\\dist\\query-helpers.js:95:19\n at Object.getByRole (C:\\Users\\Connor\\.codex\\worktrees\\direct-roadmap-integration\\Job tracker\\job-tracker-ui\\src\\correspondence-inbox-page.test.tsx:730:44)"],"fullName":"CorrespondenceInboxPage hidden or inactive details never resume a saved-copy fallback and hub return preserves inbox context","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"startAt":1793773309843,"status":"failed","title":"hidden or inactive details never resume a saved-copy fallback and hub return preserves inbox context"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":273,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage provider status Retry is isolated from saved messages and drafts and live locale changes cause no reads","invocations":1,"location":null,"numPassingAsserts":11,"retryReasons":[],"startAt":1793773310145,"status":"passed","title":"provider status Retry is isolated from saved messages and drafts and live locale changes cause no reads"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":4184,"failing":false,"failureDetails":[{}],"failureMessages":["TypeError: Expected container to be an Element, a Document or a DocumentFragment but got null.\n\nIgnored nodes: comments, script, style\n\u001b[36m\u001b[39m\n \u001b[36m
\u001b[39m\n \u001b[0mReconnect this provider with send access to reply from JobTracker.\u001b[0m\n \u001b[36m
\u001b[39m\n \u001b[36m
\u001b[39m\n \u001b[36m
\u001b[39m\n\u001b[36m\u001b[39m\n at waitForWrapper (C:\\Users\\Connor\\.codex\\worktrees\\direct-roadmap-integration\\Job tracker\\job-tracker-ui\\node_modules\\@testing-library\\dom\\dist\\wait-for.js:163:27)\n at C:\\Users\\Connor\\.codex\\worktrees\\direct-roadmap-integration\\Job tracker\\job-tracker-ui\\node_modules\\@testing-library\\dom\\dist\\query-helpers.js:86:33\n at findByRole (C:\\Users\\Connor\\.codex\\worktrees\\direct-roadmap-integration\\Job tracker\\job-tracker-ui\\src\\correspondence-inbox-page.test.tsx:126:31)"],"fullName":"CorrespondenceInboxPage en opened message retains one application action in named context","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793775285036,"status":"failed","title":"en opened message retains one application action in named context"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":4148,"failing":false,"failureDetails":[{"name":"TestingLibraryElementError"}],"failureMessages":["Error: Unable to find role=\"complementary\" and name \"Jobb\"\n\nIgnored nodes: comments, script, style\n\u001b[36m\u001b[39m\n \u001b[36m
\u001b[39m\n \u001b[0mKoble denne leverandøren til på nytt med sendetilgang for å svare fra JobTracker.\u001b[0m\n \u001b[36m
\u001b[39m\n \u001b[36m
\u001b[39m\n \u001b[36m
\u001b[39m\n\u001b[36m\u001b[39m\n at waitForWrapper (C:\\Users\\Connor\\.codex\\worktrees\\direct-roadmap-integration\\Job tracker\\job-tracker-ui\\node_modules\\@testing-library\\dom\\dist\\wait-for.js:163:27)\n at C:\\Users\\Connor\\.codex\\worktrees\\direct-roadmap-integration\\Job tracker\\job-tracker-ui\\node_modules\\@testing-library\\dom\\dist\\query-helpers.js:86:33\n at findByRole (C:\\Users\\Connor\\.codex\\worktrees\\direct-roadmap-integration\\Job tracker\\job-tracker-ui\\src\\correspondence-inbox-page.test.tsx:126:31)"],"fullName":"CorrespondenceInboxPage nb opened message retains one application action in named context","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793775289338,"status":"failed","title":"nb opened message retains one application action in named context"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage en inbox filters and messages support request-free keyboard navigation","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793775293486,"status":"pending","title":"en inbox filters and messages support request-free keyboard navigation"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage nb inbox filters and messages support request-free keyboard navigation","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793775293486,"status":"pending","title":"nb inbox filters and messages support request-free keyboard navigation"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage [P7-11 inbox] resumed draft fallback metadata follows locale without mutating stored prose or refetching","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793775293486,"status":"pending","title":"[P7-11 inbox] resumed draft fallback metadata follows locale without mutating stored prose or refetching"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage renders correspondence inbox items and reloads with filters","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793775293486,"status":"pending","title":"renders correspondence inbox items and reloads with filters"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage keeps saved correspondence visible when provider status is unavailable","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793775293486,"status":"pending","title":"keeps saved correspondence visible when provider status is unavailable"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage opens provider-backed plain-text message detail in the hub","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793775293486,"status":"pending","title":"opens provider-backed plain-text message detail in the hub"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage navigates beyond the first correspondence page","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793775293486,"status":"pending","title":"navigates beyond the first correspondence page"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage unlinks a Gmail thread only after confirmation and returns it to review","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793775293486,"status":"pending","title":"unlinks a Gmail thread only after confirmation and returns it to review"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage falls back to the saved copy when provider detail is unavailable","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793775293486,"status":"pending","title":"falls back to the saved copy when provider detail is unavailable"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage keeps replies editable and requires final send confirmation","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793775293486,"status":"pending","title":"keeps replies editable and requires final send confirmation"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage saves an incomplete reply with its server delivery identity","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793775293486,"status":"pending","title":"saves an incomplete reply with its server delivery identity"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage resumes a saved draft and surfaces revision conflicts without overwriting it","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793775293486,"status":"pending","title":"resumes a saved draft and surfaces revision conflicts without overwriting it"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage persists a new delivery identity only after a definitive failed attempt","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793775293486,"status":"pending","title":"persists a new delivery identity only after a definitive failed attempt"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage starts a new-message draft only from an owned job and send-capable provider choice","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793775293486,"status":"pending","title":"starts a new-message draft only from an owned job and send-capable provider choice"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage searches the complete server-side job choice set while composing","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793775293486,"status":"pending","title":"searches the complete server-side job choice set while composing"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage does not offer retry when delivery is uncertain","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793775293486,"status":"pending","title":"does not offer retry when delivery is uncertain"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage uses one hub for linked messages and recruitment suggestions","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793775293486,"status":"pending","title":"uses one hub for linked messages and recruitment suggestions"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage localizes inbox controls while preserving correspondence content","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793775293486,"status":"pending","title":"localizes inbox controls while preserving correspondence content"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage legacy Gmail review route redirects into the consolidated hub filter","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793775293486,"status":"pending","title":"legacy Gmail review route redirects into the consolidated hub filter"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage failed inbox reads retain a current-language error and recover with one explicit GET-only Retry","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793775293486,"status":"pending","title":"failed inbox reads retain a current-language error and recover with one explicit GET-only Retry"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage a late old page cannot overwrite the latest query and page-one inbox snapshot","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793775293486,"status":"pending","title":"a late old page cannot overwrite the latest query and page-one inbox snapshot"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage message Retry replays the captured owned detail read without hiding it and localizes saved-copy fallback","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793775293486,"status":"pending","title":"message Retry replays the captured owned detail read without hiding it and localizes saved-copy fallback"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage hidden or inactive details never resume a saved-copy fallback and hub return preserves inbox context","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793775293486,"status":"pending","title":"hidden or inactive details never resume a saved-copy fallback and hub return preserves inbox context"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage provider status Retry is isolated from saved messages and drafts and live locale changes cause no reads","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793775293486,"status":"pending","title":"provider status Retry is isolated from saved messages and drafts and live locale changes cause no reads"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage confirmed unlink owns pending actions and a failed successful-write refresh recovers with GET only","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793775293486,"status":"pending","title":"confirmed unlink owns pending actions and a failed successful-write refresh recovers with GET only"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage literal all search preserves source and hash and hides another query snapshot while retaining same-query refresh data","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793775293486,"status":"pending","title":"literal all search preserves source and hash and hides another query snapshot while retaining same-query refresh data"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage typing an inbox search keeps one natural Back step to the prior screen and preserves filter context","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793775293486,"status":"pending","title":"typing an inbox search keeps one natural Back step to the prior screen and preserves filter context"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage held draft Save captures one write and locks edits, Send, Discard and every draft replacement entry","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793775293486,"status":"pending","title":"held draft Save captures one write and locks edits, Send, Discard and every draft replacement entry"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage double Review creates one confirmation, Cancel sends nothing and explicit double Send owns one captured attempt","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793775293486,"status":"pending","title":"double Review creates one confirmation, Cancel sends nothing and explicit double Send owns one captured attempt"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage recipient, subject and body edits cannot erase any recorded delivery state or rotate its attempt identity","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793775293486,"status":"pending","title":"recipient, subject and body edits cannot erase any recorded delivery state or rotate its attempt identity"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage generic 409 cannot prepare a new attempt while an authoritative failed result requires one explicit server rotation","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793775293486,"status":"pending","title":"generic 409 cannot prepare a new attempt while an authoritative failed result requires one explicit server rotation"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage recipient-only and subject-only unsaved changes require replacement and discard confirmation whose Cancel retains the draft","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793775293486,"status":"pending","title":"recipient-only and subject-only unsaved changes require replacement and discard confirmation whose Cancel retains the draft"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage saved-draft initial read and post-save refresh failures recover with GET-only Retry without replaying the successful Save","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793775293486,"status":"pending","title":"saved-draft initial read and post-save refresh failures recover with GET-only Retry without replaying the successful Save"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage a late Save after inbox unmount cannot refresh drafts or attach its result to another page","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793775293486,"status":"pending","title":"a late Save after inbox unmount cannot refresh drafts or attach its result to another page"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage a held managed-draft 409 retains recipient, subject, body and revision with current-language original Save recovery","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793775293486,"status":"pending","title":"a held managed-draft 409 retains recipient, subject, body and revision with current-language original Save recovery"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage server attempt rotation preserves three unsaved fields and their dirty state while the next send uses the new identity","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793775293486,"status":"pending","title":"server attempt rotation preserves three unsaved fields and their dirty state while the next send uses the new identity"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage a committed Save starts a fresh draft-list read despite an older pending GET and rejects the late old snapshot","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793775293486,"status":"pending","title":"a committed Save starts a fresh draft-list read despite an older pending GET and rejects the late old snapshot"}],"endTime":1793775293503,"message":" ● CorrespondenceInboxPage › en opened message retains one application action in named context\n\n Unable to find role=\"complementary\" and name \"Job\"\n\n Ignored nodes: comments, script, style\n \u001b[36m\u001b[39m\n \u001b[36m
\u001b[39m\n \u001b[0mKoble denne leverandøren til på nytt med sendetilgang for å svare fra JobTracker.\u001b[0m\n \u001b[36m
\u001b[39m\n \u001b[36m
\u001b[39m\n \u001b[36m
\u001b[39m\n \u001b[36m\u001b[39m\n\n 124 | const row = messageRow('Interview invite');\n 125 | fireEvent.click(row.getByRole('button', { name: copy('emailInboxViewMessage', {}, language) }));\n > 126 | const context = await row.findByRole('complementary', { name: copy('emailInboxJob', {}, language) });\n | ^\n 127 | expect(context).toHaveTextContent('Acme Systems');\n 128 | expect(context).toHaveTextContent('Backend Engineer');\n 129 | expect(row.getAllByRole('button', { name: copy('emailInboxOpenJob', {}, language) })).toHaveLength(1);\n\n at waitForWrapper (node_modules/@testing-library/dom/dist/wait-for.js:163:27)\n at node_modules/@testing-library/dom/dist/query-helpers.js:86:33\n at findByRole (src/correspondence-inbox-page.test.tsx:126:31)\n","name":"C:\\Users\\Connor\\.codex\\worktrees\\direct-roadmap-integration\\Job tracker\\job-tracker-ui\\src\\correspondence-inbox-page.test.tsx","startTime":1793775282395,"status":"failed","summary":""}],"wasInterrupted":false}
diff --git a/docs/ui-modernisation/visual-correction/MAIL_FLAT.md b/docs/ui-modernisation/visual-correction/MAIL_FLAT.md
new file mode 100644
index 00000000..d205b9e5
--- /dev/null
+++ b/docs/ui-modernisation/visual-correction/MAIL_FLAT.md
@@ -0,0 +1,11 @@
+# Mail rows, early navigation and recorded application context
+
+4 November 2026. Continue from published and independently verified receiptdd284782, application runtimeb31ce617. Remove the whole-inbox decorative surface, make messages divided semantic articles, and move the existing Jump to messages action before filters. Compose/draft forms and explicit send confirmation keep meaningful boundaries. The jump action remains visible only in inbox mode, matching the prior hidden inbox container. Every ref, ID, message/detail owner, provider capability guard, fallback, draft revision/conflict, explicit confirmation, uncertain-send protection and unlink handler remains unchanged.
+
+Reference comparison then identified the approved A3 right-side application context. Opened messages now place the existing recorded role/company and single Open application action in a named aside on the right above1000px. On narrower layouts the context precedes the message, preserving immediate access without scrolling through long prose. DOM order is context then message; desktop grid placement presents the primary message left/context right. Closed rows retain their original inline identity/action. No extra fetch, inferred application status or fabricated appointment is added. An independent draft can belong to a different application/thread, so its existing explicit identity, ownership and confirmed-send controls remain in their separate form.
+
+RED: both EN/NB keyboard-navigation cases reproduced the late jump control. An initial full37-case run exposed two obsolete `.MuiPaper-root` test selectors; the helper now selects the named article, preserving all detail/unlink assertions. Two additional EN/NB regressions reproduced the absent named application context. Final39 inbox cases PASSED, replacing the overlapping37 total. Context checks preserve exactly one application action on open/close and no mutation. TypeScript, full lint and verifier syntax/scoped lint PASSED. All failure reports retained. No API/server changes.
+
+Pending for this successor: settled export build, pilot and36-config mail-only144-state rendered run, independent review, source/export/evidence reconciliation and publication. Existing document journeys are skipped in mail-only mode and remain qualified by the preceding source-bound receipt; no old evidence is overwritten. The verifier checks right/stacked context geometry, single application action, request-free jump/return, inert plain text, draft save, explicit confirmation and uncertain outcome/no retry. Planned counts are not PASSED execution.
+
+NOT RUN: real mailbox/provider/delivery, native/device, integrated security or release. Earlierb31ce617 captures show the preceding mail runtime and cannot qualify these edits. No new owner decision is needed for this ordinary approved IM10 correction; final A3/full route/journey acceptance remains OPEN.
diff --git a/docs/ui-modernisation/visual-correction/MAIL_FLAT_TESTS.json b/docs/ui-modernisation/visual-correction/MAIL_FLAT_TESTS.json
new file mode 100644
index 00000000..47af4dad
--- /dev/null
+++ b/docs/ui-modernisation/visual-correction/MAIL_FLAT_TESTS.json
@@ -0,0 +1 @@
+{"numFailedTestSuites":0,"numFailedTests":0,"numPassedTestSuites":1,"numPassedTests":39,"numPendingTestSuites":0,"numPendingTests":0,"numRuntimeErrorTestSuites":0,"numTodoTests":0,"numTotalTestSuites":1,"numTotalTests":39,"openHandles":[],"snapshot":{"added":0,"didUpdate":false,"failure":false,"filesAdded":0,"filesRemoved":0,"filesRemovedList":[],"filesUnmatched":0,"filesUpdated":0,"matched":0,"total":0,"unchecked":0,"uncheckedKeysByFile":[],"unmatched":0,"updated":0},"startTime":1793775434435,"success":true,"testResults":[{"assertionResults":[{"ancestorTitles":["CorrespondenceInboxPage"],"duration":438,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage en opened message retains one application action in named context","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"startAt":1793775438287,"status":"passed","title":"en opened message retains one application action in named context"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":331,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage nb opened message retains one application action in named context","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"startAt":1793775438726,"status":"passed","title":"nb opened message retains one application action in named context"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":208,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage en inbox filters and messages support request-free keyboard navigation","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"startAt":1793775439057,"status":"passed","title":"en inbox filters and messages support request-free keyboard navigation"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":195,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage nb inbox filters and messages support request-free keyboard navigation","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"startAt":1793775439265,"status":"passed","title":"nb inbox filters and messages support request-free keyboard navigation"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":510,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage [P7-11 inbox] resumed draft fallback metadata follows locale without mutating stored prose or refetching","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"startAt":1793775439460,"status":"passed","title":"[P7-11 inbox] resumed draft fallback metadata follows locale without mutating stored prose or refetching"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":498,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage renders correspondence inbox items and reloads with filters","invocations":1,"location":null,"numPassingAsserts":11,"retryReasons":[],"startAt":1793775439971,"status":"passed","title":"renders correspondence inbox items and reloads with filters"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":155,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage keeps saved correspondence visible when provider status is unavailable","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"startAt":1793775440470,"status":"passed","title":"keeps saved correspondence visible when provider status is unavailable"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":250,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage opens provider-backed plain-text message detail in the hub","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"startAt":1793775440625,"status":"passed","title":"opens provider-backed plain-text message detail in the hub"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":274,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage navigates beyond the first correspondence page","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"startAt":1793775440876,"status":"passed","title":"navigates beyond the first correspondence page"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":217,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage unlinks a Gmail thread only after confirmation and returns it to review","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"startAt":1793775441150,"status":"passed","title":"unlinks a Gmail thread only after confirmation and returns it to review"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":215,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage falls back to the saved copy when provider detail is unavailable","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"startAt":1793775441367,"status":"passed","title":"falls back to the saved copy when provider detail is unavailable"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":1177,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage keeps replies editable and requires final send confirmation","invocations":1,"location":null,"numPassingAsserts":14,"retryReasons":[],"startAt":1793775441582,"status":"passed","title":"keeps replies editable and requires final send confirmation"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":583,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage saves an incomplete reply with its server delivery identity","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"startAt":1793775442759,"status":"passed","title":"saves an incomplete reply with its server delivery identity"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":449,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage resumes a saved draft and surfaces revision conflicts without overwriting it","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"startAt":1793775443342,"status":"passed","title":"resumes a saved draft and surfaces revision conflicts without overwriting it"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":730,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage persists a new delivery identity only after a definitive failed attempt","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"startAt":1793775443791,"status":"passed","title":"persists a new delivery identity only after a definitive failed attempt"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":695,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage starts a new-message draft only from an owned job and send-capable provider choice","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"startAt":1793775444521,"status":"passed","title":"starts a new-message draft only from an owned job and send-capable provider choice"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":615,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage searches the complete server-side job choice set while composing","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"startAt":1793775445217,"status":"passed","title":"searches the complete server-side job choice set while composing"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":825,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage does not offer retry when delivery is uncertain","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"startAt":1793775445833,"status":"passed","title":"does not offer retry when delivery is uncertain"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":249,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage uses one hub for linked messages and recruitment suggestions","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"startAt":1793775446658,"status":"passed","title":"uses one hub for linked messages and recruitment suggestions"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":133,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage localizes inbox controls while preserving correspondence content","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"startAt":1793775446907,"status":"passed","title":"localizes inbox controls while preserving correspondence content"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":121,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage legacy Gmail review route redirects into the consolidated hub filter","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"startAt":1793775447040,"status":"passed","title":"legacy Gmail review route redirects into the consolidated hub filter"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":202,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage failed inbox reads retain a current-language error and recover with one explicit GET-only Retry","invocations":1,"location":null,"numPassingAsserts":13,"retryReasons":[],"startAt":1793775447161,"status":"passed","title":"failed inbox reads retain a current-language error and recover with one explicit GET-only Retry"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":302,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage a late old page cannot overwrite the latest query and page-one inbox snapshot","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"startAt":1793775447363,"status":"passed","title":"a late old page cannot overwrite the latest query and page-one inbox snapshot"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":390,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage message Retry replays the captured owned detail read without hiding it and localizes saved-copy fallback","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"startAt":1793775447665,"status":"passed","title":"message Retry replays the captured owned detail read without hiding it and localizes saved-copy fallback"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":765,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage hidden or inactive details never resume a saved-copy fallback and hub return preserves inbox context","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"startAt":1793775448055,"status":"passed","title":"hidden or inactive details never resume a saved-copy fallback and hub return preserves inbox context"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":293,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage provider status Retry is isolated from saved messages and drafts and live locale changes cause no reads","invocations":1,"location":null,"numPassingAsserts":11,"retryReasons":[],"startAt":1793775448820,"status":"passed","title":"provider status Retry is isolated from saved messages and drafts and live locale changes cause no reads"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":604,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage confirmed unlink owns pending actions and a failed successful-write refresh recovers with GET only","invocations":1,"location":null,"numPassingAsserts":13,"retryReasons":[],"startAt":1793775449113,"status":"passed","title":"confirmed unlink owns pending actions and a failed successful-write refresh recovers with GET only"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":758,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage literal all search preserves source and hash and hides another query snapshot while retaining same-query refresh data","invocations":1,"location":null,"numPassingAsserts":29,"retryReasons":[],"startAt":1793775449717,"status":"passed","title":"literal all search preserves source and hash and hides another query snapshot while retaining same-query refresh data"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":277,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage typing an inbox search keeps one natural Back step to the prior screen and preserves filter context","invocations":1,"location":null,"numPassingAsserts":14,"retryReasons":[],"startAt":1793775450476,"status":"passed","title":"typing an inbox search keeps one natural Back step to the prior screen and preserves filter context"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":785,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage held draft Save captures one write and locks edits, Send, Discard and every draft replacement entry","invocations":1,"location":null,"numPassingAsserts":15,"retryReasons":[],"startAt":1793775450753,"status":"passed","title":"held draft Save captures one write and locks edits, Send, Discard and every draft replacement entry"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":1198,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage double Review creates one confirmation, Cancel sends nothing and explicit double Send owns one captured attempt","invocations":1,"location":null,"numPassingAsserts":14,"retryReasons":[],"startAt":1793775451538,"status":"passed","title":"double Review creates one confirmation, Cancel sends nothing and explicit double Send owns one captured attempt"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":4618,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage recipient, subject and body edits cannot erase any recorded delivery state or rotate its attempt identity","invocations":1,"location":null,"numPassingAsserts":70,"retryReasons":[],"startAt":1793775452737,"status":"passed","title":"recipient, subject and body edits cannot erase any recorded delivery state or rotate its attempt identity"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":1609,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage generic 409 cannot prepare a new attempt while an authoritative failed result requires one explicit server rotation","invocations":1,"location":null,"numPassingAsserts":14,"retryReasons":[],"startAt":1793775457355,"status":"passed","title":"generic 409 cannot prepare a new attempt while an authoritative failed result requires one explicit server rotation"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":2191,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage recipient-only and subject-only unsaved changes require replacement and discard confirmation whose Cancel retains the draft","invocations":1,"location":null,"numPassingAsserts":22,"retryReasons":[],"startAt":1793775458964,"status":"passed","title":"recipient-only and subject-only unsaved changes require replacement and discard confirmation whose Cancel retains the draft"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":784,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage saved-draft initial read and post-save refresh failures recover with GET-only Retry without replaying the successful Save","invocations":1,"location":null,"numPassingAsserts":13,"retryReasons":[],"startAt":1793775461155,"status":"passed","title":"saved-draft initial read and post-save refresh failures recover with GET-only Retry without replaying the successful Save"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":391,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage a late Save after inbox unmount cannot refresh drafts or attach its result to another page","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"startAt":1793775461939,"status":"passed","title":"a late Save after inbox unmount cannot refresh drafts or attach its result to another page"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":729,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage a held managed-draft 409 retains recipient, subject, body and revision with current-language original Save recovery","invocations":1,"location":null,"numPassingAsserts":11,"retryReasons":[],"startAt":1793775462330,"status":"passed","title":"a held managed-draft 409 retains recipient, subject, body and revision with current-language original Save recovery"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":1420,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage server attempt rotation preserves three unsaved fields and their dirty state while the next send uses the new identity","invocations":1,"location":null,"numPassingAsserts":15,"retryReasons":[],"startAt":1793775463059,"status":"passed","title":"server attempt rotation preserves three unsaved fields and their dirty state while the next send uses the new identity"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":646,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage a committed Save starts a fresh draft-list read despite an older pending GET and rejects the late old snapshot","invocations":1,"location":null,"numPassingAsserts":11,"retryReasons":[],"startAt":1793775464479,"status":"passed","title":"a committed Save starts a fresh draft-list read despite an older pending GET and rejects the late old snapshot"}],"endTime":1793775465127,"message":"","name":"C:\\Users\\Connor\\.codex\\worktrees\\direct-roadmap-integration\\Job tracker\\job-tracker-ui\\src\\correspondence-inbox-page.test.tsx","startTime":1793775435385,"status":"passed","summary":""}],"wasInterrupted":false}
diff --git a/docs/ui-modernisation/visual-correction/MAIL_JUMP_RED.json b/docs/ui-modernisation/visual-correction/MAIL_JUMP_RED.json
new file mode 100644
index 00000000..33ea2ba5
--- /dev/null
+++ b/docs/ui-modernisation/visual-correction/MAIL_JUMP_RED.json
@@ -0,0 +1 @@
+{"numFailedTestSuites":1,"numFailedTests":2,"numPassedTestSuites":0,"numPassedTests":0,"numPendingTestSuites":0,"numPendingTests":35,"numRuntimeErrorTestSuites":0,"numTodoTests":0,"numTotalTestSuites":1,"numTotalTests":37,"openHandles":[],"snapshot":{"added":0,"didUpdate":false,"failure":false,"filesAdded":0,"filesRemoved":0,"filesRemovedList":[],"filesUnmatched":0,"filesUpdated":0,"matched":0,"total":0,"unchecked":0,"uncheckedKeysByFile":[],"unmatched":0,"updated":0},"startTime":1793773274821,"success":false,"testResults":[{"assertionResults":[{"ancestorTitles":["CorrespondenceInboxPage"],"duration":303,"failing":false,"failureDetails":[{"matcherResult":{"message":"expect(received).toBeTruthy()\n\nReceived: 0","pass":false}}],"failureMessages":["Error: expect(received).toBeTruthy()\n\nReceived: 0\n at toBeTruthy (C:\\Users\\Connor\\.codex\\worktrees\\direct-roadmap-integration\\Job tracker\\job-tracker-ui\\src\\correspondence-inbox-page.test.tsx:127:85)"],"fullName":"CorrespondenceInboxPage en inbox filters and messages support request-free keyboard navigation","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793773278975,"status":"failed","title":"en inbox filters and messages support request-free keyboard navigation"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":122,"failing":false,"failureDetails":[{"matcherResult":{"message":"expect(received).toBeTruthy()\n\nReceived: 0","pass":false}}],"failureMessages":["Error: expect(received).toBeTruthy()\n\nReceived: 0\n at toBeTruthy (C:\\Users\\Connor\\.codex\\worktrees\\direct-roadmap-integration\\Job tracker\\job-tracker-ui\\src\\correspondence-inbox-page.test.tsx:127:85)"],"fullName":"CorrespondenceInboxPage nb inbox filters and messages support request-free keyboard navigation","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793773279298,"status":"failed","title":"nb inbox filters and messages support request-free keyboard navigation"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage [P7-11 inbox] resumed draft fallback metadata follows locale without mutating stored prose or refetching","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793773279420,"status":"pending","title":"[P7-11 inbox] resumed draft fallback metadata follows locale without mutating stored prose or refetching"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage renders correspondence inbox items and reloads with filters","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793773279420,"status":"pending","title":"renders correspondence inbox items and reloads with filters"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage keeps saved correspondence visible when provider status is unavailable","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793773279420,"status":"pending","title":"keeps saved correspondence visible when provider status is unavailable"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage opens provider-backed plain-text message detail in the hub","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793773279420,"status":"pending","title":"opens provider-backed plain-text message detail in the hub"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage navigates beyond the first correspondence page","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793773279420,"status":"pending","title":"navigates beyond the first correspondence page"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage unlinks a Gmail thread only after confirmation and returns it to review","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793773279420,"status":"pending","title":"unlinks a Gmail thread only after confirmation and returns it to review"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage falls back to the saved copy when provider detail is unavailable","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793773279420,"status":"pending","title":"falls back to the saved copy when provider detail is unavailable"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage keeps replies editable and requires final send confirmation","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793773279420,"status":"pending","title":"keeps replies editable and requires final send confirmation"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage saves an incomplete reply with its server delivery identity","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793773279420,"status":"pending","title":"saves an incomplete reply with its server delivery identity"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage resumes a saved draft and surfaces revision conflicts without overwriting it","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793773279420,"status":"pending","title":"resumes a saved draft and surfaces revision conflicts without overwriting it"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage persists a new delivery identity only after a definitive failed attempt","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793773279420,"status":"pending","title":"persists a new delivery identity only after a definitive failed attempt"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage starts a new-message draft only from an owned job and send-capable provider choice","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793773279420,"status":"pending","title":"starts a new-message draft only from an owned job and send-capable provider choice"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage searches the complete server-side job choice set while composing","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793773279420,"status":"pending","title":"searches the complete server-side job choice set while composing"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage does not offer retry when delivery is uncertain","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793773279420,"status":"pending","title":"does not offer retry when delivery is uncertain"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage uses one hub for linked messages and recruitment suggestions","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793773279421,"status":"pending","title":"uses one hub for linked messages and recruitment suggestions"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage localizes inbox controls while preserving correspondence content","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793773279421,"status":"pending","title":"localizes inbox controls while preserving correspondence content"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage legacy Gmail review route redirects into the consolidated hub filter","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793773279421,"status":"pending","title":"legacy Gmail review route redirects into the consolidated hub filter"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage failed inbox reads retain a current-language error and recover with one explicit GET-only Retry","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793773279421,"status":"pending","title":"failed inbox reads retain a current-language error and recover with one explicit GET-only Retry"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage a late old page cannot overwrite the latest query and page-one inbox snapshot","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793773279421,"status":"pending","title":"a late old page cannot overwrite the latest query and page-one inbox snapshot"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage message Retry replays the captured owned detail read without hiding it and localizes saved-copy fallback","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793773279421,"status":"pending","title":"message Retry replays the captured owned detail read without hiding it and localizes saved-copy fallback"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage hidden or inactive details never resume a saved-copy fallback and hub return preserves inbox context","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793773279421,"status":"pending","title":"hidden or inactive details never resume a saved-copy fallback and hub return preserves inbox context"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage provider status Retry is isolated from saved messages and drafts and live locale changes cause no reads","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793773279421,"status":"pending","title":"provider status Retry is isolated from saved messages and drafts and live locale changes cause no reads"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage confirmed unlink owns pending actions and a failed successful-write refresh recovers with GET only","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793773279421,"status":"pending","title":"confirmed unlink owns pending actions and a failed successful-write refresh recovers with GET only"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage literal all search preserves source and hash and hides another query snapshot while retaining same-query refresh data","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793773279421,"status":"pending","title":"literal all search preserves source and hash and hides another query snapshot while retaining same-query refresh data"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage typing an inbox search keeps one natural Back step to the prior screen and preserves filter context","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793773279421,"status":"pending","title":"typing an inbox search keeps one natural Back step to the prior screen and preserves filter context"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage held draft Save captures one write and locks edits, Send, Discard and every draft replacement entry","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793773279421,"status":"pending","title":"held draft Save captures one write and locks edits, Send, Discard and every draft replacement entry"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage double Review creates one confirmation, Cancel sends nothing and explicit double Send owns one captured attempt","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793773279421,"status":"pending","title":"double Review creates one confirmation, Cancel sends nothing and explicit double Send owns one captured attempt"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage recipient, subject and body edits cannot erase any recorded delivery state or rotate its attempt identity","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793773279421,"status":"pending","title":"recipient, subject and body edits cannot erase any recorded delivery state or rotate its attempt identity"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage generic 409 cannot prepare a new attempt while an authoritative failed result requires one explicit server rotation","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793773279421,"status":"pending","title":"generic 409 cannot prepare a new attempt while an authoritative failed result requires one explicit server rotation"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage recipient-only and subject-only unsaved changes require replacement and discard confirmation whose Cancel retains the draft","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793773279421,"status":"pending","title":"recipient-only and subject-only unsaved changes require replacement and discard confirmation whose Cancel retains the draft"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage saved-draft initial read and post-save refresh failures recover with GET-only Retry without replaying the successful Save","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793773279421,"status":"pending","title":"saved-draft initial read and post-save refresh failures recover with GET-only Retry without replaying the successful Save"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage a late Save after inbox unmount cannot refresh drafts or attach its result to another page","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793773279421,"status":"pending","title":"a late Save after inbox unmount cannot refresh drafts or attach its result to another page"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage a held managed-draft 409 retains recipient, subject, body and revision with current-language original Save recovery","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793773279421,"status":"pending","title":"a held managed-draft 409 retains recipient, subject, body and revision with current-language original Save recovery"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage server attempt rotation preserves three unsaved fields and their dirty state while the next send uses the new identity","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793773279421,"status":"pending","title":"server attempt rotation preserves three unsaved fields and their dirty state while the next send uses the new identity"},{"ancestorTitles":["CorrespondenceInboxPage"],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"CorrespondenceInboxPage a committed Save starts a fresh draft-list read despite an older pending GET and rejects the late old snapshot","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793773279421,"status":"pending","title":"a committed Save starts a fresh draft-list read despite an older pending GET and rejects the late old snapshot"}],"endTime":1793773279433,"message":" ● CorrespondenceInboxPage › en inbox filters and messages support request-free keyboard navigation\n\n expect(received).toBeTruthy()\n\n Received: 0\n\n 125 | const jump = screen.getByRole('button', { name: copy('emailInboxJumpMessages', {}, language) });\n 126 | const search = screen.getByRole('textbox', { name: copy('correspondenceSearch', {}, language) });\n > 127 | expect(jump.compareDocumentPosition(search) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy();\n | ^\n 128 | fireEvent.click(jump);\n 129 | expect(screen.getByRole('region', { name: copy('emailInboxLinkedMessages', {}, language) })).toHaveFocus();\n 130 | fireEvent.click(screen.getByRole('button', { name: copy('emailInboxReturnFilters', {}, language) }));\n\n at toBeTruthy (src/correspondence-inbox-page.test.tsx:127:85)\n\n ● CorrespondenceInboxPage › nb inbox filters and messages support request-free keyboard navigation\n\n expect(received).toBeTruthy()\n\n Received: 0\n\n 125 | const jump = screen.getByRole('button', { name: copy('emailInboxJumpMessages', {}, language) });\n 126 | const search = screen.getByRole('textbox', { name: copy('correspondenceSearch', {}, language) });\n > 127 | expect(jump.compareDocumentPosition(search) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy();\n | ^\n 128 | fireEvent.click(jump);\n 129 | expect(screen.getByRole('region', { name: copy('emailInboxLinkedMessages', {}, language) })).toHaveFocus();\n 130 | fireEvent.click(screen.getByRole('button', { name: copy('emailInboxReturnFilters', {}, language) }));\n\n at toBeTruthy (src/correspondence-inbox-page.test.tsx:127:85)\n","name":"C:\\Users\\Connor\\.codex\\worktrees\\direct-roadmap-integration\\Job tracker\\job-tracker-ui\\src\\correspondence-inbox-page.test.tsx","startTime":1793773275899,"status":"failed","summary":""}],"wasInterrupted":false}
diff --git a/job-tracker-ui/scripts/verify-a3-documents-inbox.mjs b/job-tracker-ui/scripts/verify-a3-documents-inbox.mjs
index cbfe4bd7..9832201f 100644
--- a/job-tracker-ui/scripts/verify-a3-documents-inbox.mjs
+++ b/job-tracker-ui/scripts/verify-a3-documents-inbox.mjs
@@ -8,9 +8,10 @@ import assert from 'node:assert/strict';
const compiled = ts.transpileModule(fs.readFileSync(new URL('../src/i18n/translations.ts', import.meta.url), 'utf8'), { compilerOptions: { module: ts.ModuleKind.ESNext } }).outputText;
const { translations } = await import(`data:text/javascript;base64,${Buffer.from(compiled).toString('base64')}`);
const visualMatrix = process.env.A3_VISUAL_MATRIX === '1';
+const mailOnly = process.env.A3_MAIL_FLAT === '1';
const widths = process.env.A3_PILOT ? [320] : visualMatrix ? [320, 360, 390, 430, 768, 1024, 1280, 1440, 1920] : [320, 390, 768, 1440];
const expectedJourneys = widths.length * (process.env.A3_PILOT ? 1 : 4);
-const out = path.resolve(import.meta.dirname, visualMatrix ? '../../docs/ui-modernisation/visual-correction/evidence/documents-inbox' : '../../docs/ui-modernisation/evidence/documents-inbox/browser'); fs.mkdirSync(out, { recursive: true });
+const out = path.resolve(import.meta.dirname, mailOnly ? '../../docs/ui-modernisation/visual-correction/evidence/mail-flat' : visualMatrix ? '../../docs/ui-modernisation/visual-correction/evidence/documents-inbox' : '../../docs/ui-modernisation/evidence/documents-inbox/browser'); fs.mkdirSync(out, { recursive: true });
const report = { screens: [], journeys: [], errors: [], unexpectedWrites: [], mockedWrites: [], unavailableReads: [], blockedExternal: [] };
const browser = await chromium.launch();
try {
@@ -56,6 +57,7 @@ try {
const axe = await new AxeBuilder({ page }).withTags(['wcag2a', 'wcag2aa', 'wcag21aa', 'wcag22aa']).analyze(); report.screens.push({ width, language, mode, state, capture: target ? 'targeted viewport' : width >= 768 ? 'full page at top' : 'viewport at top', violations: axe.violations }); assert.deepEqual(axe.violations, []);
await page.screenshot({ path: path.join(out, `${state}-${language}-${mode}-${width}.png`), fullPage: width >= 768 && !target });
};
+ if (!mailOnly) {
await page.goto('http://localhost:4338/documents');
const docs = page.getByRole('region', { name: t('documentsYourDocuments'), exact: true }); await docs.getByText(document.name, { exact: true }).waitFor(); await scan('documents');
const reads = documentReads; await page.getByRole('button', { name: t('documentsJumpResults'), exact: true }).press('Enter'); assert.equal(await docs.evaluate(node => node === window.document.activeElement), true);
@@ -63,17 +65,25 @@ try {
await search.fill('certificate'); await expect(docs.getByText(cv.name, { exact: true })).toHaveCount(0); await docs.getByText(document.name, { exact: true }).waitFor();
const download = page.waitForEvent('download'); await docs.getByRole('button', { name: t('documentsDownloadAttachment'), exact: true }).click(); const file = await download; assert.equal(file.suggestedFilename(), document.name); assert.equal(fs.readFileSync(await file.path(), 'utf8'), 'Controlled certificate fixture');
assert.equal(await docs.getByRole('link', { name: t('documentsOpenSource'), exact: true }).getAttribute('href'), document.sourceHref); assert.equal(await docs.locator('time').getAttribute('datetime'), document.recordedAt); await scan('document-filtered', docs.getByText(document.name, { exact: true }));
+ }
await page.goto('http://localhost:4338/correspondence'); const messages = page.getByRole('region', { name: t('emailInboxLinkedMessages'), exact: true }); await messages.getByText(mail.subject, { exact: true }).waitFor(); await scan('inbox');
const initialMailReads = mailReads; await page.getByRole('button', { name: t('emailInboxJumpMessages'), exact: true }).press('Enter'); await expect(messages).toBeFocused(); await messages.getByRole('button', { name: t('emailInboxReturnFilters'), exact: true }).click(); await expect(page.getByRole('textbox', { name: t('correspondenceSearch'), exact: true })).toBeFocused(); assert.equal(mailReads, initialMailReads);
- await messages.getByRole('button', { name: t('emailInboxViewMessage'), exact: true }).click(); const messageBody = messages.getByText('Please choose an interview time. ', { exact: true }); await messageBody.waitFor(); await scan('message', messageBody);
+ await messages.getByRole('button', { name: t('emailInboxViewMessage'), exact: true }).click(); const messageBody = messages.getByText('Please choose an interview time. ', { exact: true }); await messageBody.waitFor();
+ const article = messages.getByRole('article', { name: mail.subject, exact: true });
+ const applicationContext = article.getByRole('complementary', { name: t('emailInboxJob'), exact: true });
+ await expect(applicationContext).toContainText(mail.jobTitle); await expect(applicationContext).toContainText(mail.companyName);
+ await expect(article.getByRole('button', { name: t('emailInboxOpenJob'), exact: true })).toHaveCount(1);
+ const contentBounds = await article.locator('[data-mail-message-content]').boundingBox(), contextBounds = await applicationContext.boundingBox();
+ assert.ok(width > 1000 ? contextBounds.x >= contentBounds.x + contentBounds.width - 2 && Math.abs(contextBounds.y - contentBounds.y) < 2 : contextBounds.y + contextBounds.height <= contentBounds.y + 2, 'Recorded application context is right on desktop and before the body on narrow screens');
+ await scan('message', messageBody);
await messages.getByRole('button', { name: t('emailInboxReply'), exact: true }).click(); const compose = page.getByRole('region', { name: t('emailInboxDraftTitle'), exact: true });
await compose.getByRole('textbox', { name: t('emailInboxRecipient'), exact: true }).fill('recruiter@example.test'); await compose.getByRole('textbox', { name: t('emailInboxMessage'), exact: true }).fill('Thank you. Please confirm the available interview times.');
await compose.getByRole('button', { name: t('emailInboxSaveDraft'), exact: true }).click(); await expect.poll(() => draft?.revision).toBe(4);
await compose.getByRole('button', { name: t('emailInboxReviewSend'), exact: true }).click(); const dialog = page.getByRole('dialog', { name: t('emailInboxConfirmSendTitle'), exact: true }); await dialog.waitFor(); assert.equal(sends, 0); await scan('send-confirmation', dialog);
await dialog.getByRole('button', { name: t('emailInboxSendEmail'), exact: true }).click(); await compose.getByText(t('emailInboxDeliveryUncertain'), { exact: true }).waitFor(); await expect(compose.getByRole('button', { name: t('emailInboxReviewSend'), exact: true })).toBeDisabled();
assert.equal(sends, 1); await expect(compose.getByRole('textbox', { name: t('emailInboxMessage'), exact: true })).toHaveValue(draft.bodyText); await scan('uncertain-send', compose.getByRole('textbox', { name: t('emailInboxMessage'), exact: true }));
- report.journeys.push({ width, language, mode, documentFilterFocusDownloadSource: 'PASS', inboxFocusPlainTextReplySaveExplicitConfirmUncertainNoRetry: 'PASS' }); await context.close();
+ report.journeys.push({ width, language, mode, documentFilterFocusDownloadSource: mailOnly ? 'NOT RUN' : 'PASS', inboxFocusPlainTextReplySaveExplicitConfirmUncertainNoRetry: 'PASS' }); await context.close();
}
- assert.equal(report.journeys.length, expectedJourneys); assert.equal(report.screens.length, report.journeys.length * 6); assert.equal(report.mockedWrites.length, report.journeys.length * 2); assert.deepEqual(report.errors, []); assert.deepEqual(report.unexpectedWrites, []); assert.ok(report.blockedExternal.every(origin => origin === 'https://fonts.googleapis.com'));
+ assert.equal(report.journeys.length, expectedJourneys); assert.equal(report.screens.length, report.journeys.length * (mailOnly ? 4 : 6)); assert.equal(report.mockedWrites.length, report.journeys.length * 2); assert.deepEqual(report.errors, []); assert.deepEqual(report.unexpectedWrites, []); assert.ok(report.blockedExternal.every(origin => origin === 'https://fonts.googleapis.com'));
console.log(`PASS:${report.journeys.length} document/mail journeys,${report.screens.length} axe scans/captures,${report.mockedWrites.length} fixture-only save/send requests.`);
} finally { fs.writeFileSync(path.join(out, process.env.A3_PILOT ? 'PILOT.json' : 'BROWSER.json'), JSON.stringify({ ...report, limits: ['Synthetic metadata/binary/mail/provider fixtures; not live storage, mailbox, OAuth or delivery.', 'Browser covers draft save, explicit confirmation and controlled uncertain outcome only; other recovery/conflict paths remain targeted tests.', 'No real sending, native device, final integrated security or release acceptance.'] }, null, 2)); await browser.close(); }
diff --git a/job-tracker-ui/src/correspondence-inbox-page.test.tsx b/job-tracker-ui/src/correspondence-inbox-page.test.tsx
index c3b65f75..6261737e 100644
--- a/job-tracker-ui/src/correspondence-inbox-page.test.tsx
+++ b/job-tracker-ui/src/correspondence-inbox-page.test.tsx
@@ -53,7 +53,7 @@ function pageData(items: ReturnType[], page = 1, total = ite
}
function messageRow(subject: string) {
- return within(screen.getByText(subject, { exact: true }).closest('.MuiPaper-root') as HTMLElement);
+ return within(screen.getByRole('article', { name: subject }));
}
function LocationProbe() {
@@ -118,11 +118,29 @@ function renderPage(initialPath = '/') {
}
describe('CorrespondenceInboxPage', () => {
+ test.each(['en', 'nb'] as const)('%s opened message retains one application action in named context', async language => {
+ localStorage.setItem('uiLanguage', language); renderPage();
+ await screen.findByText('Interview invite', { exact: true });
+ const row = messageRow('Interview invite');
+ fireEvent.click(row.getByRole('button', { name: copy('emailInboxViewMessage', {}, language) }));
+ const context = await row.findByRole('complementary', { name: copy('emailInboxJob', {}, language) });
+ expect(context).toHaveTextContent('Acme Systems');
+ expect(context).toHaveTextContent('Backend Engineer');
+ expect(row.getAllByRole('button', { name: copy('emailInboxOpenJob', {}, language) })).toHaveLength(1);
+ expect(within(context).getByRole('button', { name: copy('emailInboxOpenJob', {}, language) })).toBeEnabled();
+ fireEvent.click(row.getByRole('button', { name: copy('emailInboxHideMessage', {}, language) }));
+ expect(row.queryByRole('complementary')).not.toBeInTheDocument();
+ expect(row.getAllByRole('button', { name: copy('emailInboxOpenJob', {}, language) })).toHaveLength(1);
+ expect(mockedApi.post).not.toHaveBeenCalled(); expect(mockedApi.put).not.toHaveBeenCalled(); expect(mockedApi.delete).not.toHaveBeenCalled();
+ });
test.each(['en', 'nb'] as const)('%s inbox filters and messages support request-free keyboard navigation', async language => {
localStorage.setItem('uiLanguage', language); renderPage();
await screen.findByText('Interview invite', { exact: true });
const count = mockedApi.get.mock.calls.length;
- fireEvent.click(screen.getByRole('button', { name: copy('emailInboxJumpMessages', {}, language) }));
+ const jump = screen.getByRole('button', { name: copy('emailInboxJumpMessages', {}, language) });
+ const search = screen.getByRole('textbox', { name: copy('correspondenceSearch', {}, language) });
+ expect(jump.compareDocumentPosition(search) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy();
+ fireEvent.click(jump);
expect(screen.getByRole('region', { name: copy('emailInboxLinkedMessages', {}, language) })).toHaveFocus();
fireEvent.click(screen.getByRole('button', { name: copy('emailInboxReturnFilters', {}, language) }));
expect(screen.getByRole('textbox', { name: copy('correspondenceSearch', {}, language) })).toHaveFocus();
diff --git a/job-tracker-ui/src/views/CorrespondenceInboxPage.tsx b/job-tracker-ui/src/views/CorrespondenceInboxPage.tsx
index 312babab..07f18687 100644
--- a/job-tracker-ui/src/views/CorrespondenceInboxPage.tsx
+++ b/job-tracker-ui/src/views/CorrespondenceInboxPage.tsx
@@ -675,7 +675,7 @@ export default function CorrespondenceInboxPage() {
};
return (
-
+ messagesPanel.current?.focus()}>{t("emailInboxJumpMessages")} : undefined}>
{view === "inbox" && hasCurrentInbox ? } label={t(inboxTotal === 1 ? "emailInboxItem" : "emailInboxItems", { count: inboxTotal })} variant="outlined" /> : null}
@@ -777,7 +777,6 @@ export default function CorrespondenceInboxPage() {
-
{draft ? (
@@ -830,10 +829,10 @@ export default function CorrespondenceInboxPage() {
{(hasCurrentInbox ? items : []).map((item) => (
-
+
- {item.companyName || t("emailInboxUnknownCompany")} • {item.jobTitle || t("emailInboxUnknownRole")}
+ {selectedMessageId !== item.id ? {item.companyName || t("emailInboxUnknownCompany")} • {item.jobTitle || t("emailInboxUnknownRole")} : null}
{item.subject || item.contentPreview || t("emailInboxNoSubject")}
{item.externalFrom || item.from} {item.externalTo ? `→ ${item.externalTo}` : ""} · {new Date(item.date).toLocaleString(language === "nb" ? "nb-NO" : "en")}
@@ -846,7 +845,7 @@ export default function CorrespondenceInboxPage() {
{item.labelCount > 0 ? : null}
{item.attachmentCount > 0 ? : null}
-
+ {selectedMessageId !== item.id ? : null}
{item.provider === "gmail" && item.externalThreadId ? (
{selectedMessageId === item.id ? (
-
+
+
+ {t("emailInboxJob")}
+ {item.jobTitle || t("emailInboxUnknownRole")}
+ {item.companyName || t("emailInboxUnknownCompany")}
+
+
+ { detailPanel.current?.focus({ preventScroll: true }); return detailItem.current ? loadMessage(detailItem.current) : undefined; }} />
{detailNotice ? {t("emailInboxProviderCopyUnavailable")} : null}
{messageDetail ? <>
@@ -872,9 +878,10 @@ export default function CorrespondenceInboxPage() {
{t("emailInboxReconnectToReply")}
) : null}
> : null}
+
) : null}
-
+
))}
{hasCurrentInbox && inboxTotalPages > 1 ? (