--- name: project-artifact-overview-click-through-bug description: "RESOLVED 2026-08-06 (re-verified by direct file read): all 3 gaps fixed — data-artifact-id, #/artifacts/:id route, and mountArtifactBrowser(initialArtifactId) all present." metadata: type: project --- **RESOLVED as of 2026-08-06** (re-verified by reading `frontend/app.js` directly while investigating the unrelated Org Graph click-through bug, see [[project-org-strip-click-through-bug]]): all three gaps below have been fixed. `renderArtifactSummaryList`/`renderArtifactSummaryList`'s `
  • ` now carries `data-artifact-id` (app.js:1360), `ARTIFACT_DETAIL_RE` (`#/artifacts/:id`) is a real dynamic route wired in `render()` (app.js:99,125-129), and `mountArtifactBrowser(initialArtifactId)` (app.js:1603) seeds `selectedArtifactId` from it and calls the existing `showPreview()` flow. Don't re-flag this as open without re-reading the file first — but do keep re-verifying, per CLAUDE.md's general warning that autonomous self-hosting runs can fix or re-break things between sessions. **Original investigation (2026-08-04)**, kept for history — root cause was real and narrower than it first looked, three separate gaps, not one: 1. `renderArtifactSummaryList()` (frontend/app.js:1344) renders bare `
  • ` with no `data-artifact-id` and no click handler — confirmed, matches the task's stated root cause. 2. The router (`frontend/app.js:77-132`, `routes` object + `render()`) does exact-string lookup on `window.location.hash` (`routes[hash]`), with only two regex-based dynamic routes today: `TASK_DETAIL_RE` (`#/tasks/:id`) and `SKILL_AUDIT_RE` (`#/skills/:id/audit`). There is **no query-string parsing anywhere** in the router — a hash like `#/artifacts?artifact_id=xxx` would fail `routes[hash]` *and* both regexes and fall through to "Not found". Fixing this bug requires extending routing (either a new `#/artifacts/:id`-style dynamic route matched the same way as `TASK_DETAIL_RE`, or adding query-string stripping/parsing to `render()` before route lookup) — it is not just a matter of adding an `href`. 3. `mountArtifactBrowser()` (frontend/app.js:1582) already has the exact mechanism needed to *display* a specific artifact once you have its id — `showPreview(artifactId)` sets `selectedArtifactId` and fetches `/api/artifacts/:id` — but it is only ever invoked from a click on `li[data-artifact-id]` inside `refreshList()`, never from a URL param. The comment at app.js:1353-1356 ("v_artifact_browser and v_task_board don't parse URL query params today ... out of scope") was written about the *"查看全部"* link specifically (intentionally unfiltered) — it is not evidence that per-item deep-linking is already supported or was rejected; don't misread it as covering this case. **How to apply**: when writing the SDD for this task, the technical design must cover (a) adding `data-artifact-id` + click → hash navigation in `renderArtifactSummaryList`, (b) a route-level change (new dynamic route or hash query-parsing) so `#/artifacts` can carry an artifact id, and (c) `mountArtifactBrowser` reading that id on mount and calling the existing `showPreview()`/`refreshList()` flow to preselect it — reusing `c_artifact_get` / `GET /api/artifacts/:artifact_id` as-is, no new content-preview logic. The "查看全部" links (app.js:1387-1390) must keep pointing at plain `#/artifacts` / `#/tasks` — do not add the id param to those.