-
Notifications
You must be signed in to change notification settings - Fork 1
docs: record ADRs for the Ask Agent temporal/lineage/evidence goal #422
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
734ca3e
docs: record ADRs for the Ask Agent temporal/lineage/evidence goal
seonghobae 1c89fee
Merge remote-tracking branch 'origin/worktree-fix-frontend-build-brea…
seonghobae cb54525
docs: renumber Ask Agent ADRs 0119-0122 to 0150-0153
seonghobae c1b290d
docs: refresh product technical gap baseline
seonghobae 1ae0aa9
docs: record armed acceptance queue
seonghobae bcd881c
fix(frontend): repair the inherited login/admin-panel build break
seonghobae c54b172
Merge PR 475 baseline safety repair into Ask docs
seonghobae 9b8d3af
Merge remote-tracking branch 'origin/main' into HEAD
seonghobae 9853f84
Merge remote-tracking branch 'origin/main' into worktree-ask-agent-docs
seonghobae File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| # ADR 0150: Global Ask resolves Korean relative-time expressions | ||
|
|
||
| - Status: Accepted | ||
| - Date: 2026-08-22 | ||
| - Related: [0047](0047-global-ask-semantic-retrieval.md), [0090](0090-global-ask-lineage-timeline-expansion.md) | ||
|
|
||
| ## Context | ||
|
|
||
| A question like "어제 무슨 일이 있었나요?" ("what happened yesterday?") names a | ||
| time window the reader already has in mind. Before this decision, | ||
| `gather_global_chat_sources`'s keyword retrieval (ADR 0047) had no way to | ||
| use that window: "어제" only ever became a literal search token against | ||
| post titles and bodies, indistinguishable from any other two-character | ||
| term. A fresh, unrelated post that happened to rank highest on unrelated | ||
| keyword overlap could outrank the post the reader actually meant. | ||
|
|
||
| ## Decision | ||
|
|
||
| `lineageweave.temporal_expressions.resolve_korean_relative_time` is a pure | ||
| date-arithmetic function (no database or network access) that resolves a | ||
| question's first Korean relative-time expression into an inclusive | ||
| `(start_date, end_date)` window. It covers 오늘/어제/그제(그저께)/그끄제(그끄저께), | ||
| 작년/재작년/올해/내년, 작년·재작년 이맘때(쯤) (a ±5-day fuzz window around the | ||
| anniversary date, since "-쯤" means "approximately"), 지난/이번/다음 주/달, and | ||
| the general "N일/주/개월/년 전" pattern. "언젠가" ("someday") resolves to no | ||
| bound -- the reader has explicitly declined to name one, which is the same | ||
| retrieval behavior as finding no expression at all. | ||
|
|
||
| `gather_global_chat_sources` applies the resolved window as an additional | ||
| `created_at` bound on its final ABAC-filtered candidate query, additive to | ||
| the existing keyword-match ranking -- it narrows the already-ranked | ||
| candidate set, it does not replace ranking with a date filter. Matched | ||
| temporal literals are excluded from keyword-term extraction | ||
| (`TEMPORAL_STOPWORDS`) so a resolved expression does not also become a | ||
| near-meaningless literal search term. | ||
|
|
||
| ## Considered alternatives | ||
|
|
||
| - Send the raw question to an LLM to extract a date range: rejected for the | ||
| same reason ADR 0047's keyword step avoids ungrounded LLM inference at | ||
| the retrieval boundary -- a hallucinated date range would silently | ||
| narrow (or widen) the candidate set with no way for the reader to verify | ||
| it, and every extra provider round-trip is retrieval latency the reader | ||
| pays before seeing an answer. | ||
| - Resolve to a single anchor day for the generalized "N주/N개월 전" pattern | ||
| (mirroring "N일 전"): rejected -- "2 weeks ago" means that whole week to | ||
| a reader, not one arbitrary day inside it, so `_week_range`/`_month_range` | ||
| are used instead, matching how the named "지난주"/"지난달" patterns already | ||
| behave. | ||
|
|
||
| ## Consequences | ||
|
|
||
| - Global Ask can now answer time-scoped questions without the relative-time | ||
| term itself acting as retrieval noise. | ||
| - The resolver is locale-specific (Korean only); a question in another | ||
| supported UI locale (ADR on i18n scope, `frontend/src/i18n.ts`) that | ||
| names a relative time in that language still falls back to keyword-only | ||
| retrieval. Extending to additional locales is a follow-up, not required | ||
| by this decision. | ||
| - `today` is always passed explicitly by the caller (server-local date); | ||
| the resolver itself never reads the wall clock, keeping it a pure, | ||
| trivially unit-testable function. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| # ADR 0151: Global Ask renders every cited thread as its own branch graph | ||
|
|
||
| - Status: Accepted | ||
| - Date: 2026-08-22 | ||
| - Related: [0090](0090-global-ask-lineage-timeline-expansion.md), [0064](0064-lineage-evidence-and-tree-assembly.md) | ||
|
|
||
| ## Context | ||
|
|
||
| ADR 0090 expands only the single top-ranked match through its direct | ||
| `post_lineage_edge` neighbors, so an answer could speak to at most one | ||
| connected timeline. A Global Ask answer frequently cites posts from more | ||
| than one unrelated reconstruct thread -- two separate customer complaints | ||
| that happen to share a keyword, for example -- and before this decision | ||
| the reader had no way to see how (or whether) those threads relate to each | ||
| other; the answer's text evidence facts named a lineage relationship in | ||
| prose only for the single expanded anchor. | ||
|
|
||
| Separately, `LineageDag`/`layoutLineageDag` (the post-detail popup's Event | ||
| Lineage visualization) already renders one `LineageGraph` payload as N | ||
| independent branch-tree `<figure>`s, one per reconstruct thread (bucketed | ||
| by `LineageGraphNode.group`, `lineageLayout.ts`'s `layoutLineageDag`). | ||
| Each thread's own tree is laid out with git-log-style branch/merge | ||
| semantics (`is_root`, `is_branch_point`) already -- there was no missing | ||
| git-branch-style layout to build, only missing graph *data* for Global | ||
| Ask to feed that existing component. | ||
|
|
||
| ## Decision | ||
|
|
||
| `lineage_graphs_for_posts` (`backend/app/lineage_ingestion.py`) merges | ||
| every cited post's full reconstructed thread into one `LineageGraph` | ||
| payload: it calls the existing, ABAC-checked `visible_lineage_graph` once | ||
| per cited post id and deduplicates nodes/edges shared across citations. | ||
| `POST /api/ask` returns this as a new `lineage_graph` response field. | ||
| `AskAgentPanel` renders `<LineageDag>` under the answer whenever that | ||
| field carries nodes -- reusing the post-detail popup's exact rendering | ||
| component, so citing posts from two unrelated threads produces two | ||
| independent branch-tree figures with no new frontend layout code. | ||
|
|
||
| ## Considered alternatives | ||
|
|
||
| - Build a new, Ask-specific multi-graph component: rejected -- | ||
| `LineageDag` already does exactly this (grouped, branch-aware, per-thread | ||
| figures); a second implementation would only risk drifting from the | ||
| post-detail popup's established visual language and accessibility | ||
| behavior for the same underlying data shape. | ||
| - Bound the merged graph to the single top-cited post's thread, matching | ||
| ADR 0090's scope: rejected -- that reintroduces the original gap this | ||
| decision addresses (a multi-thread answer showing only one thread). | ||
|
|
||
| ## Consequences | ||
|
|
||
| - An Ask answer's lineage evidence is now visually traceable per cited | ||
| thread, not summarized as prose for one anchor post only. | ||
| - `lineage_graphs_for_posts` issues one `visible_lineage_graph` call per | ||
| cited post (each a bounded `source_post` scan plus a full | ||
| `post_lineage_edge` table read); acceptable at the current citation cap | ||
| (`_POST_CHAT_SOURCE_LIMIT` = 8) and the existing `visible_lineage_graph` | ||
| precedent for the post-detail popup, revisit with a single batched query | ||
| if the citation cap grows materially. | ||
| - The response payload grows by one field (`lineage_graph`); existing | ||
| consumers that ignore unknown fields are unaffected. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| # ADR 0152: Global Ask cites persisted image evidence, never raw bytes | ||
|
|
||
| - Status: Accepted | ||
| - Date: 2026-08-22 | ||
| - Related: [0066](0066-position-preserving-image-content.md), [0039](0039-global-ask-agent-source-boundary.md) | ||
|
|
||
| ## Context | ||
|
|
||
| An Ask answer citing a post whose evidence actually came from an embedded | ||
| picture (a screenshot, a diagram) read as an unmarked text claim -- the | ||
| reader had no way to tell the citation was image-sourced rather than | ||
| drawn from the post's written body. Separately, no code path in this | ||
| repository ever sends embedded image bytes to a client: `post_content_image` | ||
| persists each image's OCR text, caption, and tags (ADR 0066), and | ||
| `GET /api/posts/{id}/content` already returns only that description, never | ||
| the image itself. `lineageweave.image_content`'s normalization step | ||
| likewise replaces every embedded image with a bracketed text placeholder | ||
| before any LLM or API response is built. | ||
|
|
||
| ## Decision | ||
|
|
||
| "Cite images" is satisfied inside that existing, deliberate boundary | ||
| rather than by adding a new image-serving mechanism. `cited_post_images` | ||
| (`backend/app/post_chat_ingestion.py`) reads `post_content_image`/ | ||
| `post_content_image_tag` for the already-cited post ids and returns their | ||
| persisted `mime_type`, `caption`, `extracted_text`, and `tags` -- the same | ||
| fields `GET /api/posts/{id}/content` renders, scoped to citations. | ||
| `POST /api/ask` returns this as a new `cited_post_images` field; the | ||
| Ask answer view renders an explicit "Image evidence" line per cited post | ||
| carrying one. | ||
|
|
||
| No additional ABAC check runs inside `cited_post_images`: `cited_post_ids` | ||
| only ever contains ids drawn from `gather_global_chat_sources`'s | ||
| already-authorized source set -- the same trust boundary | ||
| `cited_post_evidence`/`cited_post_summaries` (`lineageweave.post_chat`) | ||
| already rely on without re-checking visibility per call. | ||
|
|
||
| ## Considered alternatives | ||
|
|
||
| - Add an endpoint that serves the original image bytes for a citation: | ||
| rejected -- this would be the first place in the codebase raw embedded | ||
| image bytes ever leave the server, reopening a boundary ADR 0066 and | ||
| `lineageweave.image_content`'s normalization step deliberately closed. | ||
| Nothing about "citing" an image requires the pixels themselves; the | ||
| persisted description is the citable claim. | ||
| - Fold image evidence into the existing `cited_post_evidence` fact list | ||
| (reusing its `kind`/`text` shape): rejected -- an image's caption and | ||
| its OCR text are two independently useful strings (a diagram's caption | ||
| says what it's a diagram *of*; its OCR says what text appears *in* it), | ||
| which the flat `{kind, text}` shape cannot carry without concatenating | ||
| them into one opaque string. | ||
|
|
||
| ## Consequences | ||
|
|
||
| - A reader can now tell when an Ask citation's evidence came from a | ||
| picture rather than the post's written body, without any new image | ||
| storage or serving surface. | ||
| - The response payload grows by one field (`cited_post_images`); existing | ||
| consumers that ignore unknown fields are unaffected. | ||
| - Region-level citation (pointing at a specific area of a larger image, | ||
| as `post_content_image_region` already supports for the post-detail | ||
| popup) is not surfaced here -- a future enhancement, not required by | ||
| this decision. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| # ADR 0153: Ask citations open a focused evidence Layer Popup | ||
|
|
||
| - Status: Accepted | ||
| - Date: 2026-08-22 | ||
| - Related: [0152](0152-ask-image-citation.md), [0151](0151-ask-multi-lineage-graph.md) | ||
|
|
||
| ## Context | ||
|
|
||
| Reading one Ask citation's evidence meant either scanning the inline fact | ||
| list rendered under every citation at once, or leaving the answer | ||
| entirely to open the full post detail popup (`PostDetailPopup`) -- there | ||
| was no focused way to inspect a single citation's evidence without either | ||
| losing the answer or wading through unrelated citations' facts on screen | ||
| at the same time. | ||
|
|
||
| ## Decision | ||
|
|
||
| `AskEvidenceLayerPopup` (`frontend/src/components/`) is a new, focused | ||
| modal opened by a "View evidence" button on each citation. It shows only | ||
| that one cited post's text evidence facts (ADR 0047's evidence chips) and | ||
| image evidence (ADR 0152) without navigating away from the answer or | ||
| displaying any other citation's evidence. It reuses the app's existing | ||
| `.popup-backdrop`/`.popup-panel` visual language (`PostDetailPopup`'s own | ||
| classes) rather than introducing a new modal style. | ||
|
|
||
| Its dialog semantics are stricter than `PostDetailPopup`'s: `role="dialog"`, | ||
| `aria-modal="true"`, `aria-labelledby` naming the cited post's title, | ||
| Escape-to-close, backdrop-click-to-close, and initial focus moved onto the | ||
| panel on mount. `PostDetailPopup` has none of these today; this decision | ||
| does not retrofit them there -- a focused follow-up, not silently expanded | ||
| scope of this change. | ||
|
|
||
| `chatEvidenceKindLabel` (previously a private `App.tsx` helper) moved to | ||
| `frontend/src/evidenceKindLabels.ts` so both `App.tsx` and the new | ||
| component read from one label map instead of maintaining two copies that | ||
| could drift. | ||
|
|
||
| ## Considered alternatives | ||
|
|
||
| - Extend `PostDetailPopup` itself with an "evidence-only" display mode: | ||
| rejected -- that component already fetches and renders a large surface | ||
| (summary, 5W1H, Keymen, counterparties, Event Lineage, evaluation); a | ||
| mode flag threading through all of that to suppress everything except | ||
| evidence is a larger, riskier change than a small, independent | ||
| component with its own narrow props. | ||
| - Reuse the post-scoped chat's existing `EvidencePanel` (a non-modal, | ||
| `role="complementary"` sliding panel that shows a cited post's full | ||
| body): rejected -- it fetches and renders the entire post body, not | ||
| scoped facts/images, and its non-modal layout assumes the post-scoped | ||
| chat's own screen real estate, which Global Ask's answer view does not | ||
| have. | ||
|
|
||
| ## Consequences | ||
|
|
||
| - A reader can inspect one citation's evidence in a focused layer without | ||
| losing their place in the answer. | ||
| - The Layer Popup pattern (a small, dialog-semantic overlay scoped to one | ||
| piece of evidence) is now precedent for future evidence surfaces that | ||
| don't warrant a full post detail popup. | ||
| - `PostDetailPopup`'s missing dialog semantics (no `role="dialog"`, no | ||
| Escape-to-close) remain an open accessibility gap, tracked here as a | ||
| known follow-up rather than fixed by this decision. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.