From 85bdcadb49208a4651c13ec2ebfb0e92b0d65b22 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 25 Aug 2026 18:15:50 +0900 Subject: [PATCH 1/9] fix(lineage): clear stale focused graph --- frontend/src/App.test.tsx | 18 +++++++++++------- frontend/src/App.tsx | 1 + 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/frontend/src/App.test.tsx b/frontend/src/App.test.tsx index 1fb7233fd..05a77c5ce 100644 --- a/frontend/src/App.test.tsx +++ b/frontend/src/App.test.tsx @@ -2253,13 +2253,17 @@ describe("App, authenticated", () => { "no_comparison_group" as const, "No other visible posts share this comparison group yet. Request reconstruction after more posts arrive, or read Keyman and evaluation.", ], - ])("explains an empty focused Event Lineage graph: %s", async (lineageIsolationReason, message) => { - stubBackend({ lineageIsolationReason }); - render(); - await userEvent.click(await screen.findByRole("button", { name: "View post: Public post" })); - expect(await screen.findByText(message)).toBeInTheDocument(); - expect(screen.queryByText("No linked posts yet.")).not.toBeInTheDocument(); - }); + ])( + "explains an empty focused Event Lineage graph: %s", + async (lineageIsolationReason, message) => { + stubBackend({ lineageIsolationReason }); + render(); + await userEvent.click(await screen.findByRole("button", { name: "View post: Public post" })); + expect(await screen.findByText(message)).toBeInTheDocument(); + expect(screen.queryByText("No linked posts yet.")).not.toBeInTheDocument(); + }, + 15_000, + ); it("shows an embedded invoice image instead of the raw base64 string", async () => { const tinyPng = diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 1c3b53ed2..4999cf7af 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -3974,6 +3974,7 @@ function PostList({ setFocusedGraph(null); return; } + setFocusedGraph(null); let active = true; fetchLineageGraph(accessToken, selectedPostId) .then((nextGraph) => { From 54a02d39e5cb3b99dc4dcce174f05fa332379769 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 25 Aug 2026 18:20:23 +0900 Subject: [PATCH 2/9] docs: record protected merge wave --- docs/product-technical-gap-baseline.md | 32 +++++++++++++------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 4df379e4e..6e146a539 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,6 +1,6 @@ # Product & Technical Gap Baseline -> Audit snapshot: 2026-08-25 18:00 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-25 18:25 KST (refreshed by the autonomous merge > loop). This repository records synthetic fixtures and aggregate, > non-identifying runtime evidence only. Open PRs and local checks are not > protected-default-branch release evidence. Identifying post identifiers, @@ -9,18 +9,16 @@ ## 1. Exact-head and governance evidence -The protected default branch was `3d6d7188a3ae299ffef77eb991032268a4c2160d` -when this baseline was refreshed. The live queue contained 5 open PRs and 17 +The protected default branch was `3f4734806bdc7ef5843f36c7dbbcceb62cd51b9e` +when this baseline was refreshed. The live queue contained 3 open PRs and 17 open issues. The exact-head inventory below supersedes older per-PR snapshots elsewhere in this document; those older rows remain useful historical delivery context only. | PR | Exact observed head | Merge/check state at this snapshot | | ---: | --- | --- | -| #609 | `820fe648` | exact-main follow-up that renders #493's focused isolation reasons with localized next actions and an accepted ADR; backend/documentation, focused UI, i18n, lint, and build checks passed locally, auto-merge is enabled, and hosted gates plus independent review remain outstanding | -| #606 | `61fd631c` | retires the internally anchored channel-weight vector in favor of the exact TEPP#237 criterion-validity contract and contains the former #607 operations-dashboard stack; the head now conflicts with protected `main` and must be composed without losing either capability | -| #579 | `a8e9ef9e` | interaction-map coordinates remain open and now conflict with protected `main`; prior branch tests and screenshot audits do not transfer across the required composition | -| #490 | `73413d0b` | broad historical workspace branch is conflicting with failing checks; decompose/restack rather than replaying its 931-commit merge wholesale | +| #612 | `85bdcadb` | this post-#609 follow-up clears the previous focused graph during navigation so another post's isolation reason cannot flash; the documentation amendment necessarily supersedes this observed pre-amendment SHA, and auto-merge remains subject to restarted exact-head gates and review | +| #579 | `9de161ef` | interaction-map coordinates are mergeable on the current head; hosted gates and independent exact-head review remain outstanding | | #387 | `ab5cf345` | channel evidence plus Ask reconstruction-profile preservation is mergeable on the current head, but a current changes-requested decision remains; resolve valid findings and obtain independent exact-head re-review before enabling auto-merge | No row above is merge evidence. Immediately before any lifecycle action, @@ -28,19 +26,18 @@ re-fetch the head, unresolved threads, formal reviews, rulesets, and same-head check conclusions. In particular, queued checks are infrastructure state and do not transfer evidence from an earlier SHA. -PR #607 merged as `61fd631c7bb3c57113fd19763c2c43161eeb2824` -into #606's non-default branch. That stack merge preserves its implementation -but is not protected-`main` evidence; only #606's eventual protected merge can -deliver the combined TEPP-anchor and operations-dashboard work. +PR #607 first merged as `61fd631c7bb3c57113fd19763c2c43161eeb2824` +into #606's non-default branch. The complete stack subsequently passed the +protected gate and #606 merged to `main` as +`3f4734806bdc7ef5843f36c7dbbcceb62cd51b9e`. PR #604 was closed unmerged after its exact OIDC repair was composed into #605; its green or pending checks are not delivery evidence. PR #482 merged as protected-main commit `464ff25002044b9d933c8eefd36c8def7ca0ffd8` with package conflict markers, identifying baseline records, and an OIDC return-context regression. PR #603 repaired the package/privacy and -analysis-run transaction defects through protected main at `4f53190b`; the -OIDC defect remains delivered until #604 or the composed #605 passes the -protected gate. Protected main is therefore not yet a release candidate. +analysis-run transaction defects through protected main at `4f53190b`; #605 +subsequently delivered the composed OIDC repair through the protected gate. PR #592 first merged as `3b3af3b4fe9c439354433a43444e05f37ab24ea3` into #590's non-default stack base at `2f033ba3`. The complete stack then @@ -99,6 +96,9 @@ Recent protected-default-branch delivery evidence (squash merges onto | PR | Merged (UTC) | Delivered | | ---: | --- | --- | +| #606 | 2026-08-25 09:10 | exact TEPP criterion anchor plus evidence-grounded operations dashboard stack | +| #609 | 2026-08-25 09:10 | localized buyer-facing focused-isolation reasons; stale-navigation clearing continues on #612 | +| #610 | 2026-08-25 09:09 | post-merge exact-head product-gap baseline | | #468 | 2026-08-25 08:44 | fast-mlsirm, Keyverse, orchestrator, and TEPP integration boundaries | | #493 | 2026-08-25 08:44 | ABAC-safe focused Event Lineage isolation reasons in the backend; buyer copy continues on #609 | | #600 | 2026-08-25 08:44 | non-identifying live gap baseline and ADR 0109 login-helper repair | @@ -291,8 +291,8 @@ this file per §3.5 of the prior snapshot). | Gap | Current evidence | Acceptance requirement | | --- | --- | --- | -| Protected release | 5 open PRs at snapshot; #609 is mergeable with auto-merge, #606/#579/#490 conflict, and #387 retains changes requested | Terminal exact-head checks, no unresolved threads, independent exact-head approvals, protected squash-merge SHA | -| Evidence-grounded operations workspace | The former #607 implements persisted operational cases, an authenticated dashboard, citation-first actions, report/alert delivery metadata, tokens, Storybook, and regression coverage inside #606; authenticated production backfill and the similar-VOC live endpoint remain unavailable | Clear #606 normally on its exact combined head, perform authenticated desktop/mobile acceptance with aggregate evidence, and confirm a protected merge SHA | +| Protected release | 3 open PRs at snapshot; #612 and #579 are mergeable while #387 retains changes requested | Terminal exact-head checks, no unresolved threads, independent exact-head approvals, protected squash-merge SHA | +| Evidence-grounded operations workspace | Protected-main #606 delivers persisted operational cases, an authenticated dashboard, citation-first actions, report/alert delivery metadata, tokens, Storybook, and regression coverage; authenticated production backfill and the similar-VOC live endpoint remain unavailable | Perform authenticated desktop/mobile acceptance with aggregate evidence and deliver the live similar-VOC endpoint before claiming that subfeature | | Shared frontend gate | The ADR 0109 login repair is on protected `main`; eight older branches carried the defect and received the same verified repair this loop (#521–#560) | Keep every future branch cut from post-repair bases; re-verify with frontend lint/test/build before push | | Identifying baseline regression | `main` gap file listed real post identifiers; separately, closed #506 and pre-existing public history contain a private runtime source-table identifier, while current `main` and #507 trees are clean | Land this non-identifying rewrite, then coordinate ADR 0001 history remediation with security/privacy owners; do not reproduce the value, force-push, or delete evidence ad hoc | | Authorized-corpus runtime | Repository tests use synthetic fixtures; private records remain outside git | Authenticated runtime validation returning only aggregate, non-identifying evidence | From dabac11f6896a5d78a0142b3cf4d726693b12d68 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 25 Aug 2026 18:21:49 +0900 Subject: [PATCH 3/9] docs: correct current channel-evidence head --- docs/product-technical-gap-baseline.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 6e146a539..75fa3a028 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -19,7 +19,7 @@ context only. | ---: | --- | --- | | #612 | `85bdcadb` | this post-#609 follow-up clears the previous focused graph during navigation so another post's isolation reason cannot flash; the documentation amendment necessarily supersedes this observed pre-amendment SHA, and auto-merge remains subject to restarted exact-head gates and review | | #579 | `9de161ef` | interaction-map coordinates are mergeable on the current head; hosted gates and independent exact-head review remain outstanding | -| #387 | `ab5cf345` | channel evidence plus Ask reconstruction-profile preservation is mergeable on the current head, but a current changes-requested decision remains; resolve valid findings and obtain independent exact-head re-review before enabling auto-merge | +| #387 | `b14725f2` | channel evidence plus Ask reconstruction-profile preservation now conflicts with protected `main`; current review also flags one unused calendar import, so composition and that minimal cleanup must precede fresh exact-head gates and independent re-review | No row above is merge evidence. Immediately before any lifecycle action, re-fetch the head, unresolved threads, formal reviews, rulesets, and same-head @@ -291,7 +291,7 @@ this file per §3.5 of the prior snapshot). | Gap | Current evidence | Acceptance requirement | | --- | --- | --- | -| Protected release | 3 open PRs at snapshot; #612 and #579 are mergeable while #387 retains changes requested | Terminal exact-head checks, no unresolved threads, independent exact-head approvals, protected squash-merge SHA | +| Protected release | 3 open PRs at snapshot; #612 and #579 are mergeable while #387 requires conflict composition and review cleanup | Terminal exact-head checks, no unresolved threads, independent exact-head approvals, protected squash-merge SHA | | Evidence-grounded operations workspace | Protected-main #606 delivers persisted operational cases, an authenticated dashboard, citation-first actions, report/alert delivery metadata, tokens, Storybook, and regression coverage; authenticated production backfill and the similar-VOC live endpoint remain unavailable | Perform authenticated desktop/mobile acceptance with aggregate evidence and deliver the live similar-VOC endpoint before claiming that subfeature | | Shared frontend gate | The ADR 0109 login repair is on protected `main`; eight older branches carried the defect and received the same verified repair this loop (#521–#560) | Keep every future branch cut from post-repair bases; re-verify with frontend lint/test/build before push | | Identifying baseline regression | `main` gap file listed real post identifiers; separately, closed #506 and pre-existing public history contain a private runtime source-table identifier, while current `main` and #507 trees are clean | Land this non-identifying rewrite, then coordinate ADR 0001 history remediation with security/privacy owners; do not reproduce the value, force-push, or delete evidence ad hoc | From ee98e28fe2e04d23de2c6d09e65736027cb4c63b Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 25 Aug 2026 18:22:39 +0900 Subject: [PATCH 4/9] Revert "docs: correct current channel-evidence head" This reverts commit dabac11f6896a5d78a0142b3cf4d726693b12d68. --- docs/product-technical-gap-baseline.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 75fa3a028..6e146a539 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -19,7 +19,7 @@ context only. | ---: | --- | --- | | #612 | `85bdcadb` | this post-#609 follow-up clears the previous focused graph during navigation so another post's isolation reason cannot flash; the documentation amendment necessarily supersedes this observed pre-amendment SHA, and auto-merge remains subject to restarted exact-head gates and review | | #579 | `9de161ef` | interaction-map coordinates are mergeable on the current head; hosted gates and independent exact-head review remain outstanding | -| #387 | `b14725f2` | channel evidence plus Ask reconstruction-profile preservation now conflicts with protected `main`; current review also flags one unused calendar import, so composition and that minimal cleanup must precede fresh exact-head gates and independent re-review | +| #387 | `ab5cf345` | channel evidence plus Ask reconstruction-profile preservation is mergeable on the current head, but a current changes-requested decision remains; resolve valid findings and obtain independent exact-head re-review before enabling auto-merge | No row above is merge evidence. Immediately before any lifecycle action, re-fetch the head, unresolved threads, formal reviews, rulesets, and same-head @@ -291,7 +291,7 @@ this file per §3.5 of the prior snapshot). | Gap | Current evidence | Acceptance requirement | | --- | --- | --- | -| Protected release | 3 open PRs at snapshot; #612 and #579 are mergeable while #387 requires conflict composition and review cleanup | Terminal exact-head checks, no unresolved threads, independent exact-head approvals, protected squash-merge SHA | +| Protected release | 3 open PRs at snapshot; #612 and #579 are mergeable while #387 retains changes requested | Terminal exact-head checks, no unresolved threads, independent exact-head approvals, protected squash-merge SHA | | Evidence-grounded operations workspace | Protected-main #606 delivers persisted operational cases, an authenticated dashboard, citation-first actions, report/alert delivery metadata, tokens, Storybook, and regression coverage; authenticated production backfill and the similar-VOC live endpoint remain unavailable | Perform authenticated desktop/mobile acceptance with aggregate evidence and deliver the live similar-VOC endpoint before claiming that subfeature | | Shared frontend gate | The ADR 0109 login repair is on protected `main`; eight older branches carried the defect and received the same verified repair this loop (#521–#560) | Keep every future branch cut from post-repair bases; re-verify with frontend lint/test/build before push | | Identifying baseline regression | `main` gap file listed real post identifiers; separately, closed #506 and pre-existing public history contain a private runtime source-table identifier, while current `main` and #507 trees are clean | Land this non-identifying rewrite, then coordinate ADR 0001 history remediation with security/privacy owners; do not reproduce the value, force-push, or delete evidence ad hoc | From e38d7678979eabd9486f017075a6859e78ecf7c7 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 25 Aug 2026 18:22:39 +0900 Subject: [PATCH 5/9] Revert "docs: record protected merge wave" This reverts commit 54a02d39e5cb3b99dc4dcce174f05fa332379769. --- docs/product-technical-gap-baseline.md | 32 +++++++++++++------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 6e146a539..4df379e4e 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,6 +1,6 @@ # Product & Technical Gap Baseline -> Audit snapshot: 2026-08-25 18:25 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-25 18:00 KST (refreshed by the autonomous merge > loop). This repository records synthetic fixtures and aggregate, > non-identifying runtime evidence only. Open PRs and local checks are not > protected-default-branch release evidence. Identifying post identifiers, @@ -9,16 +9,18 @@ ## 1. Exact-head and governance evidence -The protected default branch was `3f4734806bdc7ef5843f36c7dbbcceb62cd51b9e` -when this baseline was refreshed. The live queue contained 3 open PRs and 17 +The protected default branch was `3d6d7188a3ae299ffef77eb991032268a4c2160d` +when this baseline was refreshed. The live queue contained 5 open PRs and 17 open issues. The exact-head inventory below supersedes older per-PR snapshots elsewhere in this document; those older rows remain useful historical delivery context only. | PR | Exact observed head | Merge/check state at this snapshot | | ---: | --- | --- | -| #612 | `85bdcadb` | this post-#609 follow-up clears the previous focused graph during navigation so another post's isolation reason cannot flash; the documentation amendment necessarily supersedes this observed pre-amendment SHA, and auto-merge remains subject to restarted exact-head gates and review | -| #579 | `9de161ef` | interaction-map coordinates are mergeable on the current head; hosted gates and independent exact-head review remain outstanding | +| #609 | `820fe648` | exact-main follow-up that renders #493's focused isolation reasons with localized next actions and an accepted ADR; backend/documentation, focused UI, i18n, lint, and build checks passed locally, auto-merge is enabled, and hosted gates plus independent review remain outstanding | +| #606 | `61fd631c` | retires the internally anchored channel-weight vector in favor of the exact TEPP#237 criterion-validity contract and contains the former #607 operations-dashboard stack; the head now conflicts with protected `main` and must be composed without losing either capability | +| #579 | `a8e9ef9e` | interaction-map coordinates remain open and now conflict with protected `main`; prior branch tests and screenshot audits do not transfer across the required composition | +| #490 | `73413d0b` | broad historical workspace branch is conflicting with failing checks; decompose/restack rather than replaying its 931-commit merge wholesale | | #387 | `ab5cf345` | channel evidence plus Ask reconstruction-profile preservation is mergeable on the current head, but a current changes-requested decision remains; resolve valid findings and obtain independent exact-head re-review before enabling auto-merge | No row above is merge evidence. Immediately before any lifecycle action, @@ -26,18 +28,19 @@ re-fetch the head, unresolved threads, formal reviews, rulesets, and same-head check conclusions. In particular, queued checks are infrastructure state and do not transfer evidence from an earlier SHA. -PR #607 first merged as `61fd631c7bb3c57113fd19763c2c43161eeb2824` -into #606's non-default branch. The complete stack subsequently passed the -protected gate and #606 merged to `main` as -`3f4734806bdc7ef5843f36c7dbbcceb62cd51b9e`. +PR #607 merged as `61fd631c7bb3c57113fd19763c2c43161eeb2824` +into #606's non-default branch. That stack merge preserves its implementation +but is not protected-`main` evidence; only #606's eventual protected merge can +deliver the combined TEPP-anchor and operations-dashboard work. PR #604 was closed unmerged after its exact OIDC repair was composed into #605; its green or pending checks are not delivery evidence. PR #482 merged as protected-main commit `464ff25002044b9d933c8eefd36c8def7ca0ffd8` with package conflict markers, identifying baseline records, and an OIDC return-context regression. PR #603 repaired the package/privacy and -analysis-run transaction defects through protected main at `4f53190b`; #605 -subsequently delivered the composed OIDC repair through the protected gate. +analysis-run transaction defects through protected main at `4f53190b`; the +OIDC defect remains delivered until #604 or the composed #605 passes the +protected gate. Protected main is therefore not yet a release candidate. PR #592 first merged as `3b3af3b4fe9c439354433a43444e05f37ab24ea3` into #590's non-default stack base at `2f033ba3`. The complete stack then @@ -96,9 +99,6 @@ Recent protected-default-branch delivery evidence (squash merges onto | PR | Merged (UTC) | Delivered | | ---: | --- | --- | -| #606 | 2026-08-25 09:10 | exact TEPP criterion anchor plus evidence-grounded operations dashboard stack | -| #609 | 2026-08-25 09:10 | localized buyer-facing focused-isolation reasons; stale-navigation clearing continues on #612 | -| #610 | 2026-08-25 09:09 | post-merge exact-head product-gap baseline | | #468 | 2026-08-25 08:44 | fast-mlsirm, Keyverse, orchestrator, and TEPP integration boundaries | | #493 | 2026-08-25 08:44 | ABAC-safe focused Event Lineage isolation reasons in the backend; buyer copy continues on #609 | | #600 | 2026-08-25 08:44 | non-identifying live gap baseline and ADR 0109 login-helper repair | @@ -291,8 +291,8 @@ this file per §3.5 of the prior snapshot). | Gap | Current evidence | Acceptance requirement | | --- | --- | --- | -| Protected release | 3 open PRs at snapshot; #612 and #579 are mergeable while #387 retains changes requested | Terminal exact-head checks, no unresolved threads, independent exact-head approvals, protected squash-merge SHA | -| Evidence-grounded operations workspace | Protected-main #606 delivers persisted operational cases, an authenticated dashboard, citation-first actions, report/alert delivery metadata, tokens, Storybook, and regression coverage; authenticated production backfill and the similar-VOC live endpoint remain unavailable | Perform authenticated desktop/mobile acceptance with aggregate evidence and deliver the live similar-VOC endpoint before claiming that subfeature | +| Protected release | 5 open PRs at snapshot; #609 is mergeable with auto-merge, #606/#579/#490 conflict, and #387 retains changes requested | Terminal exact-head checks, no unresolved threads, independent exact-head approvals, protected squash-merge SHA | +| Evidence-grounded operations workspace | The former #607 implements persisted operational cases, an authenticated dashboard, citation-first actions, report/alert delivery metadata, tokens, Storybook, and regression coverage inside #606; authenticated production backfill and the similar-VOC live endpoint remain unavailable | Clear #606 normally on its exact combined head, perform authenticated desktop/mobile acceptance with aggregate evidence, and confirm a protected merge SHA | | Shared frontend gate | The ADR 0109 login repair is on protected `main`; eight older branches carried the defect and received the same verified repair this loop (#521–#560) | Keep every future branch cut from post-repair bases; re-verify with frontend lint/test/build before push | | Identifying baseline regression | `main` gap file listed real post identifiers; separately, closed #506 and pre-existing public history contain a private runtime source-table identifier, while current `main` and #507 trees are clean | Land this non-identifying rewrite, then coordinate ADR 0001 history remediation with security/privacy owners; do not reproduce the value, force-push, or delete evidence ad hoc | | Authorized-corpus runtime | Repository tests use synthetic fixtures; private records remain outside git | Authenticated runtime validation returning only aggregate, non-identifying evidence | From 09204a401e297c156f8f1f140320617e9553563e Mon Sep 17 00:00:00 2001 From: seonghobae Date: Tue, 25 Aug 2026 18:27:37 +0900 Subject: [PATCH 6/9] fix(lineage): keep focused graph loading fail-closed --- frontend/src/App.tsx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 4999cf7af..7d6ad756b 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -3823,7 +3823,6 @@ function PostList({ onPostOpened?: () => void; }) { const [posts, setPosts] = useState(null); - const [graph, setGraph] = useState(null); const [focusedGraph, setFocusedGraph] = useState(null); const [error, setError] = useState(null); const [selectedPostId, setSelectedPostId] = useState(null); @@ -3955,7 +3954,6 @@ function PostList({ }, [loadPostPage]); useEffect(() => { - fetchLineageGraph(accessToken).then(setGraph).catch(() => setGraph({ nodes: [], edges: [] })); fetchMe(accessToken) .then((me) => { setCanRebuild(me.permission_codes.includes("post_admin")); @@ -3993,7 +3991,6 @@ function PostList({ setRebuildError(null); try { await rebuildLineage(accessToken); - setGraph(await fetchLineageGraph(accessToken)); } catch (err) { setRebuildError(String(err)); } finally { @@ -4305,7 +4302,7 @@ function PostList({ postId={selectedPostId} accessToken={accessToken} canExtract={canRebuild} - graph={focusedGraph ?? graph} + graph={focusedGraph} liveBodyWarning={ openedAfterCutoff ? analysisRunOpenedBodyWarning(openedCutoffIso) : null } From ab36c8d2dfeecb44f130f795d6cc489a9012e9ad Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 25 Aug 2026 19:11:30 +0900 Subject: [PATCH 7/9] fix(lineage): retain focused graph on reselection --- frontend/src/App.tsx | 9 +++++++-- frontend/src/focusedGraphSelection.test.ts | 9 +++++++++ frontend/src/focusedGraphSelection.ts | 4 ++++ 3 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 frontend/src/focusedGraphSelection.test.ts create mode 100644 frontend/src/focusedGraphSelection.ts diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 7d6ad756b..b45ac2308 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,6 +1,7 @@ import { AdminPanel } from "./components/AdminPanel"; import { LeftoverPairList } from "./components/LeftoverPairList"; import { WorkspaceCalendar } from "./components/WorkspaceCalendar"; +import { focusedGraphMustReset } from "./focusedGraphSelection"; import { useCallback, useEffect, useRef, useState, type ReactNode } from "react"; import { useAuth } from "react-oidc-context"; @@ -3885,8 +3886,12 @@ function PostList({ } function selectPost(postId: string, options?: SelectPostOptions) { - setSelectedPostId(postId); - setFocusedGraph(null); + setSelectedPostId((currentPostId) => { + if (focusedGraphMustReset(currentPostId, postId)) { + setFocusedGraph(null); + } + return postId; + }); setOpenedAfterCutoff(Boolean(options?.liveAfterCutoff)); setOpenedCutoffIso(options?.knowledgeCutoff ?? null); setOpenedFromReportMember(Boolean(options?.fromReportMember)); diff --git a/frontend/src/focusedGraphSelection.test.ts b/frontend/src/focusedGraphSelection.test.ts new file mode 100644 index 000000000..f8522cf67 --- /dev/null +++ b/frontend/src/focusedGraphSelection.test.ts @@ -0,0 +1,9 @@ +import { describe, expect, it } from "vitest"; +import { focusedGraphMustReset } from "./focusedGraphSelection"; + +describe("focusedGraphMustReset", () => { + it("retains a loaded graph when the already-open post is selected again", () => { + expect(focusedGraphMustReset("post-1", "post-1")).toBe(false); + expect(focusedGraphMustReset("post-1", "post-2")).toBe(true); + }); +}); diff --git a/frontend/src/focusedGraphSelection.ts b/frontend/src/focusedGraphSelection.ts new file mode 100644 index 000000000..286e4eb47 --- /dev/null +++ b/frontend/src/focusedGraphSelection.ts @@ -0,0 +1,4 @@ +/** Return whether selecting a post requires discarding the currently focused graph. */ +export function focusedGraphMustReset(currentPostId: string | null, nextPostId: string): boolean { + return currentPostId !== nextPostId; +} From 1e5b7e1c2cd2e8a7dc4e88715d978193359954bd Mon Sep 17 00:00:00 2001 From: seonghobae Date: Tue, 25 Aug 2026 18:41:45 +0900 Subject: [PATCH 8/9] fix(ui): stop WorkspaceCalendar's fail-closed placeholder announcing as role=status Its resolved empty/unavailable state carried role="status" like sibling panels' transient loading text does, so mounting it inside the Board's collapsed Advanced Review Tools details collided with every other status region on the page (4 failing App.test.tsx assertions). RankingsPanel's own resolved placeholders carry no ARIA role for the same reason -- only the "Loading..." state announces. --- frontend/src/components/WorkspaceCalendar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/WorkspaceCalendar.tsx b/frontend/src/components/WorkspaceCalendar.tsx index 5f2631f39..0b37ae2dc 100644 --- a/frontend/src/components/WorkspaceCalendar.tsx +++ b/frontend/src/components/WorkspaceCalendar.tsx @@ -33,7 +33,7 @@ export function WorkspaceCalendar({

{t("Observed calendar events")}

{events.length === 0 ? ( -

+

{naruonAvailable ? t("No observed calendar events are available.") : failClosedCopy} From 2c50d8b6d1a984344c4d6171ff4fc83a876ca7bb Mon Sep 17 00:00:00 2001 From: seonghobae Date: Tue, 25 Aug 2026 19:36:36 +0900 Subject: [PATCH 9/9] fix(ui): keep post selection updater pure --- frontend/src/App.tsx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index b45ac2308..4ea82a341 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -3886,12 +3886,10 @@ function PostList({ } function selectPost(postId: string, options?: SelectPostOptions) { - setSelectedPostId((currentPostId) => { - if (focusedGraphMustReset(currentPostId, postId)) { - setFocusedGraph(null); - } - return postId; - }); + if (focusedGraphMustReset(selectedPostId, postId)) { + setFocusedGraph(null); + } + setSelectedPostId(postId); setOpenedAfterCutoff(Boolean(options?.liveAfterCutoff)); setOpenedCutoffIso(options?.knowledgeCutoff ?? null); setOpenedFromReportMember(Boolean(options?.fromReportMember));