feat(ask): show cited-post evidence in a Layer Popup - #420
Conversation
Reading an Ask answer's evidence today means either scanning the inline fact list or leaving the answer entirely to open the full post popup. Add AskEvidenceLayerPopup (frontend/src/components/), a focused modal layer -- opened via a new "View evidence" button per citation -- showing that post's text evidence facts (checkpoint 3's cited_post_evidence) and image evidence (checkpoint 3's cited_post_images) without navigating away from the answer. Proper dialog semantics: role="dialog", aria-modal, Escape-to-close, backdrop-click-to-close, initial focus on the panel -- stricter accessibility than the existing PostDetailPopup, which has none of these. Extracted chatEvidenceKindLabel into evidenceKindLabels.ts so both App.tsx and the new component share one label map instead of drifting. Stacked on #419 (checkpoint 3): the popup's image-evidence section needs that PR's cited_post_images field to be meaningful. Part of the Ask Agent temporal/lineage/evidence goal (checkpoint 4 of 4).
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Caution Review failedAn error occurred during the review process. Please try again later. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Caution Review failedAn error occurred during the review process. Please try again later. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Caution Review failedAn error occurred during the review process. Please try again later. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Caution Review failedAn error occurred during the review process. Please try again later. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Caution Review failedAn error occurred during the review process. Please try again later. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Caution Review failedAn error occurred during the review process. Please try again later. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Caution Review failedAn error occurred during the review process. Please try again later. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Caution Review failedAn error occurred during the review process. Please try again later. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Caution Review failedAn error occurred during the review process. Please try again later. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
2 similar comments
|
Caution Review failedAn error occurred during the review process. Please try again later. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Caution Review failedAn error occurred during the review process. Please try again later. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…rsistence The pre-login screen rendered AdminPanel with a possibly-undefined accessToken (a TS6192/TS2322 build break) and never used the persisted return-URL helpers on the login redirect. Same fix as LineageWeave#456 on main, applied here since this stack predates that fix.
c7f4d6c
into
worktree-ask-agent-image-citation
|
Reviewed both current info threads at exact head |
* feat(ask): cite persisted image evidence for cited posts
An Ask answer citing a post whose evidence actually came from an
embedded picture (a screenshot, a diagram) read as an unmarked text
claim -- no way to tell the citation was image-sourced. Raw image bytes
are never sent to the client anywhere in this codebase (only persisted
OCR/caption/tags -- see lineageweave/image_content.py); this reuses that
same never-raw-bytes description GET /api/posts/{id}/content already
renders, scoped to already-cited posts.
Backend: cited_post_images (backend/app/post_chat_ingestion.py) reads
post_content_image/post_content_image_tag for the cited post ids, no
extra ABAC check needed (cited_post_ids only ever come from
gather_global_chat_sources's already-authorized source set, same trust
boundary cited_post_evidence/cited_post_summaries rely on). Wired into
POST /api/ask as a new cited_post_images response field.
Frontend: AskAgentPanel renders an "Image evidence" line under a cited
post when present, with the persisted caption and OCR text. Adds the ko
/ zh / ja / vi translations for the two new strings.
Part of the Ask Agent temporal/lineage/evidence goal (checkpoint 3 of 4).
* feat(ask): show cited-post evidence in a Layer Popup (#420)
* feat(ask): show cited-post evidence in a Layer Popup
Reading an Ask answer's evidence today means either scanning the inline
fact list or leaving the answer entirely to open the full post popup.
Add AskEvidenceLayerPopup (frontend/src/components/), a focused modal
layer -- opened via a new "View evidence" button per citation -- showing
that post's text evidence facts (checkpoint 3's cited_post_evidence) and
image evidence (checkpoint 3's cited_post_images) without navigating
away from the answer. Proper dialog semantics: role="dialog",
aria-modal, Escape-to-close, backdrop-click-to-close, initial focus on
the panel -- stricter accessibility than the existing PostDetailPopup,
which has none of these.
Extracted chatEvidenceKindLabel into evidenceKindLabels.ts so both
App.tsx and the new component share one label map instead of drifting.
Stacked on #419 (checkpoint 3): the popup's image-evidence section needs
that PR's cited_post_images field to be meaningful.
Part of the Ask Agent temporal/lineage/evidence goal (checkpoint 4 of 4).
* test(ask): cover evidence dialog edge cases
* fix(ask): contain evidence dialog focus
* docs(storybook): cover blank evidence caption
* docs(ask): trace modal accessibility standard
* docs(storybook): inventory Ask evidence layer
* docs(changelog): record Ask evidence layer
* fix(changelog): restore historical entries
* test(ask): cover modal exit focus and source transition
* fix(ask): restore focus when evidence modal exits
* fix(frontend): drop stray pre-login AdminPanel, restore return-URL persistence
The pre-login screen rendered AdminPanel with a possibly-undefined
accessToken (a TS6192/TS2322 build break) and never used the persisted
return-URL helpers on the login redirect. Same fix as LineageWeave#456
on main, applied here since this stack predates that fix.
* fix(ask): fall back to Untitled image on blank caption in AskAgentPanel
image.caption ?? t("Untitled image") only substitutes for null/undefined,
so a persisted empty-string caption rendered a blank label ("Image
evidence: — ..."). Match the blank-aware fallback already used in
AskEvidenceLayerPopup.tsx (image.caption?.trim() ? image.caption : ...)
so the same evidence renders consistently in both surfaces.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B5M79L945DMyMs3sg5yJ14
* fix: hide empty image evidence citations
* fix(frontend): render cited image tags
---------
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
) * test(e2e): add a Playwright harness for the Ask Agent capabilities No Playwright config existed despite the package already being a devDependency. Add playwright.config.ts (points at the running docker-compose stack, not a Playwright-managed dev server -- the app needs Postgres/Keycloak/Valkey/orchestrator alongside it), a real Keycloak-login helper (drives the actual OIDC redirect form with the synthetic demo.analyst credentials, not a token injected into storage), a validated smoke spec, and ask-agent.spec.ts covering all four Ask Agent capabilities (relative-time retrieval #415, multi-lineage graphs #418, image citation #419, Layer Popup #420). The login flow is verified passing against a live stack right now. ask-agent.spec.ts needs #415/#418/#419/#420 merged and the images rebuilt from main before it can pass -- verified during development that the currently-running ad-hoc stack is built from an unrelated, more advanced branch (its own conversation-history UI), not main, so it cannot validate this spec; that requires a proper CI/deployment rebuild, out of this checkpoint's scope. Part of the Ask Agent temporal/lineage/evidence goal (checkpoint 5 of 6 -- e2e harness). * fix(frontend): repair the inherited login/admin-panel build break Two TypeScript build errors on main (blocking every open PR's "Frontend lint, test, build" check, including this repo's own review bot's ability to approve them): - App.tsx imported rememberOidcReturnUrl/returnUrlFromLocation from oidcReturnUrl.ts but never called them -- the login button built its own unsanitized returnUrl inline instead of using the safe helper (oidcReturnUrl.ts's isSafeReturnUrl guard against an open-redirect- shaped value) or persisting it as the sessionStorage/localStorage fallback restoreOidcReturnUrl (already wired up on the callback side in main.tsx) reads when the OIDC state round-trip drops it. - The unauthenticated login screen unconditionally rendered <AdminPanel accessToken={accessToken} /> when destination === "admin" -- accessToken is string | undefined here (always undefined while unauthenticated), a real type error, and the render was unreachable through normal navigation (destination only changes via the authenticated nav) -- dead code, removed. uv run --frozen python -m pytest -q: 753 passed, 17 skipped. pnpm run test: 140 passed. pnpm run lint / build: clean. * test(frontend): keep Playwright specs out of Vitest * fix(e2e): stop Ask Agent lineage/image tests silently skipping their assertions The git-branch-lineage and image-citation Ask Agent tests wrapped their only real assertions in an `if (count > 0)` guard, so a run where the LLM's answer happened not to produce that citation shape would report PASS without exercising the behavior the test claims to cover. Assert the precondition itself so the test fails loudly instead. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5M79L945DMyMs3sg5yJ14 * fix(e2e): stabilize Ask Agent locale and multi-match checks --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
) * docs: record ADRs for the Ask Agent temporal/lineage/evidence goal Four new ADRs, one per checkpoint of the Ask Agent temporal/lineage/ evidence goal: - 0119: Korean relative-time expression resolution (#415) - 0120: multi-thread Event Lineage graphs in Ask answers (#418) - 0121: image citation without a new image-serving surface (#419) - 0122: the evidence Layer Popup (#420) Update CHANGELOG.md's Unreleased section and add an "Ask Agent Gaps" section to docs/product-technical-gap-baseline.md marking all four gaps (plus e2e coverage, #421) resolved, following that file's existing "(Resolved)" convention. Part of the Ask Agent temporal/lineage/evidence goal (checkpoint 6 of 6 -- documentation). * docs: renumber Ask Agent ADRs 0119-0122 to 0150-0153 Cross-session coordination surfaced a widespread ADR-numbering collision: at least ten numbers between 0119 and 0143 are independently claimed by concurrent unmerged branches across other sessions (0127/0128/0129/0131/0132 each claimed 2-4x, per `git log --all --diff-filter=A -- docs/adr`). This PR's own 0119-0122 was a three-way collision (also claimed by the TEPP topic-lineage PR and a quantity-superscript PR). Since this PR only holds 4 ADRs against another's 14 (0119-0132), renumbering here is the smaller diff. Moved clear of every number seen across all branches (highest observed: 0143), leaving buffer room. No content changes -- only the ADR number in each file's title, their mutual cross-references, and every CHANGELOG.md / gap-baseline.md citation of the old numbers. * docs: refresh product technical gap baseline * docs: record armed acceptance queue * fix(frontend): repair the inherited login/admin-panel build break Two TypeScript build errors on main (blocking every open PR's "Frontend lint, test, build" check, including this repo's own review bot's ability to approve them): - App.tsx imported rememberOidcReturnUrl/returnUrlFromLocation from oidcReturnUrl.ts but never called them -- the login button built its own unsanitized returnUrl inline instead of using the safe helper (oidcReturnUrl.ts's isSafeReturnUrl guard against an open-redirect- shaped value) or persisting it as the sessionStorage/localStorage fallback restoreOidcReturnUrl (already wired up on the callback side in main.tsx) reads when the OIDC state round-trip drops it. - The unauthenticated login screen unconditionally rendered <AdminPanel accessToken={accessToken} /> when destination === "admin" -- accessToken is string | undefined here (always undefined while unauthenticated), a real type error, and the render was unreachable through normal navigation (destination only changes via the authenticated nav) -- dead code, removed. uv run --frozen python -m pytest -q: 753 passed, 17 skipped. pnpm run test: 140 passed. pnpm run lint / build: clean. --------- Co-authored-by: seonghobae <seonghobae@users.noreply.github.com>
#420 (focused citation evidence Layer Popup, ADR 0153) is referenced in prose but was absent from the stack table because it has already merged; mark it explicitly so the table and prose agree.
Buyer-visible gap
Reading an Ask answer's evidence meant either scanning the inline fact list under each citation or leaving the answer entirely to open the full post detail popup. There was no focused way to inspect one citation's persisted evidence without losing the answer.
Change
AskEvidenceLayerPopup(frontend/src/components/): focused modal evidence for one cited post using feat(ask): cite persisted image evidence for cited posts #419'scited_post_evidenceandcited_post_images.AskAgentPanelgets a View evidence next action per citation.role="dialog",aria-modal, Escape/backdrop/close-button exit, initial focus inside, forward and reverse Tab containment, and focus restoration to the invoking control on ordinary close. Choosing Open post closes the layer before transitioning to the source-post workflow rather than stacking the two surfaces.Evidence factsname.Untitled image.chatEvidenceKindLabelis shared throughevidenceKindLabels.tsinstead of drifting betweenApp.tsxand the layer.Evidence/AskEvidenceLayerPopupcovers default, text-only, image-only, no-evidence, image-without-OCR-text, null-caption, and blank-caption states.docs/doctoring/DESIGN_TOKEN_REFERENCES.mdmaps the keyboard behavior to the WAI-ARIA APG Dialog (Modal) Pattern and records the primary-source reference in APA 7 style.Design authority
Fresh Figma metadata for file
1Su3lDRmiZdcUs47t1QwIXcontains the Ask Agent answered frames (11:2desktop,11:3mobile) and shared primary-control authority, but no dedicated evidence-layer frame. This PR therefore reuses the existing product tokens/control language and treats Storybook as the executable state catalog for this new layer; it does not claim pixel matching to a nonexistent Figma layer frame.Stacking and gate ownership
Based on #419 because image evidence needs that checkpoint's
cited_post_imagescontract. The current frontend production/Storybook build is still blocked by the two inheritedApp.tsxTypeScript errors at lines 106 and 4651. Their minimal repair is owned by #405, whose exact headb170eb4102484a104fb66462fa79a6ec129041d5has repository-native Tests/Security/SAST/PROV-O success. Do not duplicate that unrelated repair into this layer PR; merge/restack the owning dependency through its own live gates first.Exact-head verification
Exact head:
17c2f085d74c5ac22874878499d9051bf44f6752.AskEvidenceLayerPopup.test.tsxhas 8 passing tests, including blank-caption fallback, Tab/Shift+Tab containment, source-post transition ordering, and focus restoration.App.tsx(106,1)TS6192 andApp.tsx(4651,112)TS2322 errors; Storybook build is consequently skipped, not treated as passing.No real records, identifiers, or provider credentials are included.