)]}'
{
  "commit": "3c3cbbe201c2c91476dc41fe52b726293662c55e",
  "tree": "fb203e51e5264942560a9fd120198a0045dd317f",
  "parents": [
    "5844919c3d2611319c00f823e29ba7fc522b44de"
  ],
  "author": {
    "name": "AstroHan",
    "email": "lei.yuhan@outlook.com",
    "time": "Thu Aug 06 16:34:44 2026 +0800"
  },
  "committer": {
    "name": "AstroHan",
    "email": "lei.yuhan@outlook.com",
    "time": "Thu Aug 06 16:34:44 2026 +0800"
  },
  "message": "refactor(ui): give each fact behind the update entry a single writer\n\nAn adversarial review of this PR found no release blocker but two places\nwhere the change left the same fact written twice, and one place where it\nhad no way to fail.\n\nThe collapsed rail. The footer read Astryx\u0027s collapse context and stamped\nits own `data-collapsed`, while the shell was already writing\n`data-sidebar-state` on the frame and the hairline rule right above was\nalready reading it. Two markers for one state are free to disagree; the\nstacking rule now hangs off the frame, and the hook and the attribute are\ngone. Stacked, the row stretches its children to the rail\u0027s width, which\nturned a 28px circle into a 32x28 pill — the button now opts out and stays\nround at both widths.\n\nWhich states need the user. The shell narrowed the status to `downloaded`\nand `error` for the footer, then the click handler matched on the raw\nstatus again — and that second copy had already drifted, offering a retry\nfor `available` and `downloading` and falling through to a \"open the\ndownload page\" branch that nothing could reach. `updateReminderFromStatus`\nis now the one answer; the handler dispatches on its result, the\nunreachable branches are gone, and with them the two copy strings that\nonly that fallback used. The narrowing also stops claiming\n`latestVersion ?? currentVersion`: `downloaded` always carries a version\nand `error` without one is not worth a button.\n\nBoth of those were invisible to CI. The three stories are a pixel review\nsurface, not a regression net: nothing failed if the update action moved\nback inside SideNavItem\u0027s `endContent`, which is invalid HTML — a button\nin a button. `sidebar-update-entry.test.tsx` pins the markup contract\n(including a nesting-depth check that only passes while the two controls\nare siblings), and the narrowing gets unit tests over every status the\nupdater can produce.\n\nLast, the button is icon-only, so \"Restart\" was the entire accessible\nname — restart what, and why now, were in the tooltip only. The sentence\nis now both, and the two bare verbs it replaced are deleted.\n\nAlso corrects a claim in the comment that justified dropping the download\nphase: the old progress bar did not paint over its own percentage label.\nThe rule directly above it in the old CSS existed to keep the label on\ntop. The reason to drop the phase is that a silent download asks nothing\nof anyone, which stands on its own.\n",
  "tree_diff": [
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "00b1b504b836765cb6ec754f3e0a677c6ebc33df",
      "new_mode": 33188,
      "new_path": "apps/desktop/src/main/__tests__/app-shell-app-update.test.ts"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "707d9b3d3dd10e709baf8ccd7bbfae4e8d9f0b27",
      "new_mode": 33188,
      "new_path": "apps/desktop/src/renderer/app-shell-app-update.ts"
    },
    {
      "type": "modify",
      "old_id": "29b367e13d2b11f924579a297ede9555754b9dda",
      "old_mode": 33188,
      "old_path": "apps/desktop/src/renderer/app-shell.tsx",
      "new_id": "4e0e3b46f3b0c8dabe59ac3a6d282453a47cf860",
      "new_mode": 33188,
      "new_path": "apps/desktop/src/renderer/app-shell.tsx"
    },
    {
      "type": "modify",
      "old_id": "2b9657022a5fc4380390f4c7e6aaf4021098b523",
      "old_mode": 33188,
      "old_path": "apps/desktop/src/renderer/locales/shell-copy.ts",
      "new_id": "3e1a2c83236c1d620b6c616e252f9523c00be12e",
      "new_mode": 33188,
      "new_path": "apps/desktop/src/renderer/locales/shell-copy.ts"
    },
    {
      "type": "modify",
      "old_id": "1e2fb1ecd733d2f9affaf84153852d46c7218125",
      "old_mode": 33188,
      "old_path": "apps/desktop/src/renderer/styles/sidebar.css",
      "new_id": "fafd6ab0e7be72acb26e70dc47b3395a6dfb3896",
      "new_mode": 33188,
      "new_path": "apps/desktop/src/renderer/styles/sidebar.css"
    },
    {
      "type": "modify",
      "old_id": "22fd9f09119496a1b04ac5a8ff2c5841f50e4369",
      "old_mode": 33188,
      "old_path": "apps/desktop/stories/app-shell.stories.tsx",
      "new_id": "18462f36fe6b1838a9167bc44f802010f5d9792a",
      "new_mode": 33188,
      "new_path": "apps/desktop/stories/app-shell.stories.tsx"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "ad5c249d2c4e33b18d53bc1485e9f59810716de2",
      "new_mode": 33188,
      "new_path": "packages/ui/src/__tests__/sidebar-update-entry.test.tsx"
    },
    {
      "type": "modify",
      "old_id": "13c1b9da3b852cbc80fc11c5d621188bda244f89",
      "old_mode": 33188,
      "old_path": "packages/ui/src/components.tsx",
      "new_id": "ab289fc66b40642c688d6544be0149a0b1222710",
      "new_mode": 33188,
      "new_path": "packages/ui/src/components.tsx"
    },
    {
      "type": "modify",
      "old_id": "8c7a27e4ed6c0a6470b7d6f4cb586e7f5ccdd8e7",
      "old_mode": 33188,
      "old_path": "packages/ui/src/session-sidebar-nav.tsx",
      "new_id": "c92abb29acf0a91c96e631e89ac6aab01f0fe90e",
      "new_mode": 33188,
      "new_path": "packages/ui/src/session-sidebar-nav.tsx"
    },
    {
      "type": "modify",
      "old_id": "1d1b22ec7c3cd3d954a099844b45fb95cd9fe004",
      "old_mode": 33188,
      "old_path": "packages/ui/src/shell-controls-copy.ts",
      "new_id": "5221ca02f6294da0e2240c3676b153580467e256",
      "new_mode": 33188,
      "new_path": "packages/ui/src/shell-controls-copy.ts"
    }
  ]
}
