From 734ca3e348fb8e6e6b78eecda9debcf026e28656 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 17:11:33 +0900 Subject: [PATCH 1/5] 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). --- CHANGELOG.md | 15 +++++ .../0119-korean-relative-time-retrieval.md | 62 ++++++++++++++++++ docs/adr/0120-ask-multi-lineage-graph.md | 61 ++++++++++++++++++ docs/adr/0121-ask-image-citation.md | 63 +++++++++++++++++++ docs/adr/0122-ask-evidence-layer-popup.md | 62 ++++++++++++++++++ docs/product-technical-gap-baseline.md | 32 ++++++++++ 6 files changed, 295 insertions(+) create mode 100644 docs/adr/0119-korean-relative-time-retrieval.md create mode 100644 docs/adr/0120-ask-multi-lineage-graph.md create mode 100644 docs/adr/0121-ask-image-citation.md create mode 100644 docs/adr/0122-ask-evidence-layer-popup.md diff --git a/CHANGELOG.md b/CHANGELOG.md index c8ed1a099..9807b473d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,21 @@ All notable changes to this project are documented here. Format follows ## [Unreleased] +### Added + +- Global Ask now understands Korean relative-time expressions ("어제", + "작년 이맘때쯤", "재작년에", "3일 전", ...) and scopes retrieval to the + resolved date range (ADR 0119). +- Global Ask answers now render every cited post's Event Lineage thread as + its own git-branch-style graph, not a single-anchor summary (ADR 0120). +- Global Ask cites a post's persisted image evidence (caption and OCR + text) when the evidence came from an embedded picture, not just the + post's written body (ADR 0121). +- A citation's evidence can now be opened in a focused Layer Popup without + leaving the answer (ADR 0122). +- A Playwright e2e harness (`frontend/e2e/`, `pnpm run e2e`) covers the + four Ask Agent capabilities above. + ### Fixed - `make smoke` and `make seed` now run through the locked project `uv` diff --git a/docs/adr/0119-korean-relative-time-retrieval.md b/docs/adr/0119-korean-relative-time-retrieval.md new file mode 100644 index 000000000..c212ddddc --- /dev/null +++ b/docs/adr/0119-korean-relative-time-retrieval.md @@ -0,0 +1,62 @@ +# ADR 0119: 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. diff --git a/docs/adr/0120-ask-multi-lineage-graph.md b/docs/adr/0120-ask-multi-lineage-graph.md new file mode 100644 index 000000000..d5db1a44a --- /dev/null +++ b/docs/adr/0120-ask-multi-lineage-graph.md @@ -0,0 +1,61 @@ +# ADR 0120: 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 `
`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 `` 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. diff --git a/docs/adr/0121-ask-image-citation.md b/docs/adr/0121-ask-image-citation.md new file mode 100644 index 000000000..42aa36320 --- /dev/null +++ b/docs/adr/0121-ask-image-citation.md @@ -0,0 +1,63 @@ +# ADR 0121: 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. diff --git a/docs/adr/0122-ask-evidence-layer-popup.md b/docs/adr/0122-ask-evidence-layer-popup.md new file mode 100644 index 000000000..6ada99b7c --- /dev/null +++ b/docs/adr/0122-ask-evidence-layer-popup.md @@ -0,0 +1,62 @@ +# ADR 0122: Ask citations open a focused evidence Layer Popup + +- Status: Accepted +- Date: 2026-08-22 +- Related: [0121](0121-ask-image-citation.md), [0120](0120-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 0121) 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. diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index e65883463..891df82b1 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -23,4 +23,36 @@ - **Security & Compliance**: PII masking cannot break the system. Need SOC 2 and CSAP compliance alternatives to blind PII masking. - **LLM Orchestration**: Ensure ALL LLM calls route through `contextual-orchestrator` utilizing API keys (BYTEZ, NVIDIA, OPENROUTER, OPENAI) with auto model discovery and optimal reasoning effort allocation (Fugu/Conductor/TRINITY research). +## 4. Ask Agent Gaps +- **Korean relative-time understanding**: (Resolved, PR #415 / ADR 0119) + Global Ask could not answer "어제", "오늘", "그제", "작년 이맘때쯤", + "재작년에", "언젠가", or the general "N일/주/개월/년 전" pattern -- the + expression only ever became a literal keyword search term. Resolved by + `lineageweave.temporal_expressions.resolve_korean_relative_time`, wired + into `gather_global_chat_sources` as a `created_at` retrieval bound. +- **Multi-thread Event Lineage in answers**: (Resolved, PR #418 / ADR 0120) + An Ask answer could speak to at most one connected Event Lineage + timeline (ADR 0090's single-top-match expansion), shown as prose only. + Resolved by `lineage_graphs_for_posts` merging every cited post's full + thread into one `lineage_graph` response field, rendered as N + independent git-branch-style figures by the existing `LineageDag` + component. +- **Image citation in answers**: (Resolved, PR #419 / ADR 0121) A citation + whose evidence came from an embedded picture read as an unmarked text + claim. Resolved by `cited_post_images`, surfacing the same persisted + caption/OCR/tags `GET /api/posts/{id}/content` already renders, scoped + to cited posts -- no new image-serving mechanism, consistent with this + codebase's existing never-raw-bytes boundary. +- **Evidence Layer Popup**: (Resolved, PR #420 / ADR 0122) Inspecting one + citation's evidence meant either scanning every citation's facts inline + at once or leaving the answer for the full post detail popup. Resolved + by `AskEvidenceLayerPopup`, a focused modal opened per citation. +- **Ask Agent e2e coverage**: (Resolved, PR #421) No Playwright config + existed despite `playwright` already being a frontend devDependency. + Resolved by `frontend/playwright.config.ts` + `frontend/e2e/` (a + Keycloak-OIDC login helper, a verified-passing smoke spec, and a spec + covering all four capabilities above -- the latter requires PRs + #415/#418/#419/#420 merged and the images rebuilt from `main` before it + can pass; not yet true as of this entry). + *This document is continuously updated by the hourly automated agent loop.* From cb54525b5874ff1393bd61fb9dbf8570632b78fb Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 23 Aug 2026 16:07:16 +0900 Subject: [PATCH 2/5] 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. --- CHANGELOG.md | 8 ++++---- ...etrieval.md => 0150-korean-relative-time-retrieval.md} | 2 +- ...i-lineage-graph.md => 0151-ask-multi-lineage-graph.md} | 2 +- ...1-ask-image-citation.md => 0152-ask-image-citation.md} | 2 +- ...ce-layer-popup.md => 0153-ask-evidence-layer-popup.md} | 6 +++--- docs/product-technical-gap-baseline.md | 8 ++++---- 6 files changed, 14 insertions(+), 14 deletions(-) rename docs/adr/{0119-korean-relative-time-retrieval.md => 0150-korean-relative-time-retrieval.md} (98%) rename docs/adr/{0120-ask-multi-lineage-graph.md => 0151-ask-multi-lineage-graph.md} (98%) rename docs/adr/{0121-ask-image-citation.md => 0152-ask-image-citation.md} (98%) rename docs/adr/{0122-ask-evidence-layer-popup.md => 0153-ask-evidence-layer-popup.md} (93%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9807b473d..fd48823c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,14 +10,14 @@ All notable changes to this project are documented here. Format follows - Global Ask now understands Korean relative-time expressions ("어제", "작년 이맘때쯤", "재작년에", "3일 전", ...) and scopes retrieval to the - resolved date range (ADR 0119). + resolved date range (ADR 0150). - Global Ask answers now render every cited post's Event Lineage thread as - its own git-branch-style graph, not a single-anchor summary (ADR 0120). + its own git-branch-style graph, not a single-anchor summary (ADR 0151). - Global Ask cites a post's persisted image evidence (caption and OCR text) when the evidence came from an embedded picture, not just the - post's written body (ADR 0121). + post's written body (ADR 0152). - A citation's evidence can now be opened in a focused Layer Popup without - leaving the answer (ADR 0122). + leaving the answer (ADR 0153). - A Playwright e2e harness (`frontend/e2e/`, `pnpm run e2e`) covers the four Ask Agent capabilities above. diff --git a/docs/adr/0119-korean-relative-time-retrieval.md b/docs/adr/0150-korean-relative-time-retrieval.md similarity index 98% rename from docs/adr/0119-korean-relative-time-retrieval.md rename to docs/adr/0150-korean-relative-time-retrieval.md index c212ddddc..c79933e02 100644 --- a/docs/adr/0119-korean-relative-time-retrieval.md +++ b/docs/adr/0150-korean-relative-time-retrieval.md @@ -1,4 +1,4 @@ -# ADR 0119: Global Ask resolves Korean relative-time expressions +# ADR 0150: Global Ask resolves Korean relative-time expressions - Status: Accepted - Date: 2026-08-22 diff --git a/docs/adr/0120-ask-multi-lineage-graph.md b/docs/adr/0151-ask-multi-lineage-graph.md similarity index 98% rename from docs/adr/0120-ask-multi-lineage-graph.md rename to docs/adr/0151-ask-multi-lineage-graph.md index d5db1a44a..22c9a14f4 100644 --- a/docs/adr/0120-ask-multi-lineage-graph.md +++ b/docs/adr/0151-ask-multi-lineage-graph.md @@ -1,4 +1,4 @@ -# ADR 0120: Global Ask renders every cited thread as its own branch graph +# ADR 0151: Global Ask renders every cited thread as its own branch graph - Status: Accepted - Date: 2026-08-22 diff --git a/docs/adr/0121-ask-image-citation.md b/docs/adr/0152-ask-image-citation.md similarity index 98% rename from docs/adr/0121-ask-image-citation.md rename to docs/adr/0152-ask-image-citation.md index 42aa36320..ac9e456bd 100644 --- a/docs/adr/0121-ask-image-citation.md +++ b/docs/adr/0152-ask-image-citation.md @@ -1,4 +1,4 @@ -# ADR 0121: Global Ask cites persisted image evidence, never raw bytes +# ADR 0152: Global Ask cites persisted image evidence, never raw bytes - Status: Accepted - Date: 2026-08-22 diff --git a/docs/adr/0122-ask-evidence-layer-popup.md b/docs/adr/0153-ask-evidence-layer-popup.md similarity index 93% rename from docs/adr/0122-ask-evidence-layer-popup.md rename to docs/adr/0153-ask-evidence-layer-popup.md index 6ada99b7c..cf89521dd 100644 --- a/docs/adr/0122-ask-evidence-layer-popup.md +++ b/docs/adr/0153-ask-evidence-layer-popup.md @@ -1,8 +1,8 @@ -# ADR 0122: Ask citations open a focused evidence Layer Popup +# ADR 0153: Ask citations open a focused evidence Layer Popup - Status: Accepted - Date: 2026-08-22 -- Related: [0121](0121-ask-image-citation.md), [0120](0120-ask-multi-lineage-graph.md) +- Related: [0152](0152-ask-image-citation.md), [0151](0151-ask-multi-lineage-graph.md) ## Context @@ -18,7 +18,7 @@ at the same time. `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 0121) without navigating away from the answer or +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. diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 891df82b1..5c3b27938 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -24,26 +24,26 @@ - **LLM Orchestration**: Ensure ALL LLM calls route through `contextual-orchestrator` utilizing API keys (BYTEZ, NVIDIA, OPENROUTER, OPENAI) with auto model discovery and optimal reasoning effort allocation (Fugu/Conductor/TRINITY research). ## 4. Ask Agent Gaps -- **Korean relative-time understanding**: (Resolved, PR #415 / ADR 0119) +- **Korean relative-time understanding**: (Resolved, PR #415 / ADR 0150) Global Ask could not answer "어제", "오늘", "그제", "작년 이맘때쯤", "재작년에", "언젠가", or the general "N일/주/개월/년 전" pattern -- the expression only ever became a literal keyword search term. Resolved by `lineageweave.temporal_expressions.resolve_korean_relative_time`, wired into `gather_global_chat_sources` as a `created_at` retrieval bound. -- **Multi-thread Event Lineage in answers**: (Resolved, PR #418 / ADR 0120) +- **Multi-thread Event Lineage in answers**: (Resolved, PR #418 / ADR 0151) An Ask answer could speak to at most one connected Event Lineage timeline (ADR 0090's single-top-match expansion), shown as prose only. Resolved by `lineage_graphs_for_posts` merging every cited post's full thread into one `lineage_graph` response field, rendered as N independent git-branch-style figures by the existing `LineageDag` component. -- **Image citation in answers**: (Resolved, PR #419 / ADR 0121) A citation +- **Image citation in answers**: (Resolved, PR #419 / ADR 0152) A citation whose evidence came from an embedded picture read as an unmarked text claim. Resolved by `cited_post_images`, surfacing the same persisted caption/OCR/tags `GET /api/posts/{id}/content` already renders, scoped to cited posts -- no new image-serving mechanism, consistent with this codebase's existing never-raw-bytes boundary. -- **Evidence Layer Popup**: (Resolved, PR #420 / ADR 0122) Inspecting one +- **Evidence Layer Popup**: (Resolved, PR #420 / ADR 0153) Inspecting one citation's evidence meant either scanning every citation's facts inline at once or leaving the answer for the full post detail popup. Resolved by `AskEvidenceLayerPopup`, a focused modal opened per citation. From c1b290d0b06f606ba01fcb7a0638a9a5b7bed17a Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 23 Aug 2026 16:39:00 +0900 Subject: [PATCH 3/5] docs: refresh product technical gap baseline --- docs/product-technical-gap-baseline.md | 115 +++++++++++++++++++------ 1 file changed, 91 insertions(+), 24 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index e65883463..fe11172c5 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,26 +1,93 @@ # Product & Technical Gap Baseline -## 1. Known Parsing & Frontend Display Gaps -- **Footnote Parsing**: `post=00505695-3e61-1fd1-83c5-263f88a9e77a` fails to recognize footnotes (li/oi level errors). -- **Table Parsing**: `post=00505695-3e61-1fd1-80c6-86bb61c8ddc5` completely fails at parsing tables. -- **Indentation**: Incorrect indentation rendering in `post=00505695-7571-1fd1-83c3-d521b187ad5b` and `post=00505695-3e61-1fd1-83c0-497b3c1c455e`. -- **Image/Table OCR**: `post=00505695-7571-1fd1-83dd-3d22a61a5734` fails text recognition for tables inside images, markdown parsing fails, and image OCR description is too shallow for Ontology & Semantics. -- **Math/Superscripts**: `post=00505695-9612-1fe1-83a7-e30153323f25` fails to parse superscripts like m^3 properly. Needs strict Ontology grammar for math formulas. -- **Missing UI Elements**: DAG (Directed Acyclic Graph) view is currently missing from the frontend for `post=00505695-7571-1fd1-83c5-895ed333cdbc`. - -## 2. LLM Extraction & Knowledge Graph Gaps -- **Multiple Project Extraction**: (Resolved) LLM prompt updated to request key_events as objects with project_name, separating events correctly. -- **5W1H Missing**: (Resolved) LLM prompt updated to explicitly request 5W1H evidence items in the JSON output array. -- **R&R and Keyman Missing**: (Resolved) LLM prompt updated to explicitly instruct using actual stated names rather than collective titles. -- **Entity Resolution / Searxng**: Abbreviations like "한전" and "한국전력" are not mapped properly using Searxng and KG corroboration. -- **Meso-level Team Mapping**: (Resolved) Checked extraction logic; `team` mapping logic is present and correct, but LLM needed better explicit instruction which is covered by R&R resolution. -- **Base64 Image Omni-modal**: Current text-only embedding fails on images. Omni-modal LLM processing is required for images to capture layout, font size, colors, and spatial meaning. - -## 3. General Architecture Gaps -- **DB Architecture**: Ensure PostgreSQL is strictly used (no file DBs), 3rd normal form is maintained, and Hot Partitions are handled. DB locks must be managed (or use read/write replicas). -- **Zotero Integration**: Papers and standards referenced by TEPP must be synced via Local Zotero API (http://localhost:23119/api/) and cited using APA 7th edition in docstrings. -- **Testing**: We need actual testing of Psychometrics (Fast-MLSIRM parameter calibration, RMSE of estimates, Fixed-Item Parameter Calibration, CAT) against synthetic/demo data. -- **Security & Compliance**: PII masking cannot break the system. Need SOC 2 and CSAP compliance alternatives to blind PII masking. -- **LLM Orchestration**: Ensure ALL LLM calls route through `contextual-orchestrator` utilizing API keys (BYTEZ, NVIDIA, OPENROUTER, OPENAI) with auto model discovery and optimal reasoning effort allocation (Fugu/Conductor/TRINITY research). - -*This document is continuously updated by the hourly automated agent loop.* +> Audit date: 2026-08-23. This repository records synthetic fixtures and +> aggregate, non-identifying runtime evidence only. Open PRs and local checks +> are not protected-default-branch release evidence. + +## 1. Exact-head and governance evidence + +The protected default branch was +`ef6f5a5ffcb467bd935dc1e53acc0029669b0bd7` when this baseline was refreshed. +The current acceptance queue was re-fetched immediately before this update: + +| Repository | PR | Exact head | State | Remaining gate | +| --- | ---: | --- | --- | --- | +| LineageWeave | #392 | `a73d98850f985d0996bfbc4f2b1f17787710f206` | open, blocked | independent review and required protected checks | +| LineageWeave | #387 | `55a13f3473789a9481061ca2cd1f9ea042fc5902` | open, blocked, changes requested, auto-merge armed | current-head approval and Strix rerun after the central scope fix | +| LineageWeave | #405 | `0ac80616cb723a7810acae7c945fb12721a6cf7c` | open, blocked, changes requested | independent current-head approval | +| LineageWeave | #421 | `33ec5cd521bcf861db64b9f0c1faac3b3bf4deff` | open, blocked | terminal Strix result and independent review | +| LineageWeave | #426 | `11a60b370d7b5783733febb593e8f91678cc403d` | open, blocked, review required, auto-merge armed | independent current-head approval; current checks are terminal-success | +| LineageWeave | #468 | `48c7ec09d282e96b411e1060ea4ef1a769893ef9` | open, blocked | current-head protected checks and independent review | +| ContextualWisdomLab/.github | #1248 | `3f78370f3ad01409c7b2fcfb63dfb66862098fa6` | open, blocked | protected checks and independent review for the Strix scope repair | + +PR #464 merged into its stacked base as +`df413d4e58c1d05545e7970ac8cb95f197821419`. That stack-local merge does not +prove release on the default branch. + +Central PR #1248 fixes the root cause of PR #387's partial-scope false positive +by including trusted-base `backend/app/auth.py` context in backend Python Strix +scopes. Local evidence is `test_strix_quick_gate: PASS`, shell syntax success, +and `git diff --check`; the protected merge is not yet claimed. + +The organization scheduler is the single review/repair control plane. Its +`*/15 * * * *` queue sweep and `0 * * * *` heartbeat satisfy the hourly loop +requirement without a duplicate repository-local scheduler. + +## 2. Buyer-visible capability baseline + +Substantially present in source or active PRs: + +- PostgreSQL-backed import, normalized provenance, cutoff-aware analysis runs, + source revisions, lineage reconstruction, and explicit unavailable states. +- Authenticated workspace navigation, post detail, Korean summaries, 5W1H, + R&R/Keyman, evidence citations, chat, customer hierarchy, and lineage DAG. +- Semantic paragraph/list/table/image-region units that preserve the source + representation and provenance instead of flattening it into one body string. +- Contextual-orchestrator boundaries for adjudication, extraction, summaries, + chat, embeddings, and VISION; null channels remain unavailable and are + dropped from score fusion. +- W3C PROV-O projection through normalized provenance tables, with the + knowledge graph retained as an explicit navigation projection. + +These statements describe source capability, not authenticated production +corpus acceptance or protected release. + +## 3. Open product and technical gaps + +| Gap | Current evidence | Acceptance requirement | +| --- | --- | --- | +| Protected release | The listed work remains on open or stacked PR heads | Terminal exact-head checks, no unresolved threads, independent approval, and a protected merge SHA | +| Authorized-corpus runtime | Repository tests use synthetic fixtures; private records remain outside git | Authenticated runtime validation returning only aggregate, non-identifying evidence | +| Image understanding | Region/OCR/description work exists in PR #405 | Orchestrator-backed rendered workflow, original/derived asset provenance, and honest unsupported states | +| Semantic source rendering | Paragraph/table/list parsing exists across active stacks | Authenticated browser evidence that semantic units render without authoring-layout artifacts | +| Scientific measurement | TEPP and fast-mlsirm adapters are present or under review | Persisted accepted envelopes, calibration/recovery evidence, and no invented theta | +| Accessibility and responsive UX | Unit coverage exists for major buyer surfaces | Keyboard, screen-reader, mobile, and authenticated Playwright acceptance on the exact release head | +| External integrations | SearXNG, Zotero, calendar, and downstream consumer contracts are bounded | Provider conformance, failure/reconciliation behavior, and provenance-bearing integration evidence | +| Release quality | Local focused/full suites have passed on individual PR heads | Repository-wide coverage, docstrings, Storybook, security, browser, and release evidence on one exact head | + +## 4. Evidence boundaries + +- Never add a real record, title, name, identifier, screenshot, log, benchmark + artifact, or documentation example to this repository. +- Attendance or co-occurrence is not responsibility, project, customer, or + affiliation evidence. Preserve uncertainty and provenance. +- Missing transport, model capability, accepted envelope, or persistence is + unavailable/failed evidence, never a placeholder result. +- Local green tests, bot statuses, auto-merge, and warning-only checks do not + prove a protected merge. +- Re-fetch base/head SHAs, checks, review threads, approvals, rulesets, and the + merge SHA immediately before any lifecycle claim. + +## 5. Next acceptance loop + +1. Complete protected review and merge of central PR #1248, then rerun Strix + on PR #387 at the same exact head and verify the false finding is absent. +2. Re-fetch current heads, latest checks, unresolved threads, and independent + reviews for PRs #392, #405, #421, #426, and #468 before any merge claim. +3. Run frontend lint/test/build/Storybook, backend tests, and authenticated + browser/accessibility checks on the exact candidate release head. +4. Reproduce buyer cases with synthetic fixtures or authorized aggregate + runtime evidence, preserving `unavailable` explicitly. +5. Fix only evidence-backed failures and repeat the protected merge gate. Do + not self-approve, force merge/push, bypass protection, or transfer stale + review/check evidence across heads. From 1ae0aa9dbe1d462af7cba18723acc77c0fe8e5d3 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 23 Aug 2026 16:40:33 +0900 Subject: [PATCH 4/5] docs: record armed acceptance queue --- docs/product-technical-gap-baseline.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index fe11172c5..01f9482de 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -12,12 +12,12 @@ The current acceptance queue was re-fetched immediately before this update: | Repository | PR | Exact head | State | Remaining gate | | --- | ---: | --- | --- | --- | -| LineageWeave | #392 | `a73d98850f985d0996bfbc4f2b1f17787710f206` | open, blocked | independent review and required protected checks | +| LineageWeave | #392 | `a73d98850f985d0996bfbc4f2b1f17787710f206` | open, blocked, auto-merge armed | independent review and required protected checks | | LineageWeave | #387 | `55a13f3473789a9481061ca2cd1f9ea042fc5902` | open, blocked, changes requested, auto-merge armed | current-head approval and Strix rerun after the central scope fix | -| LineageWeave | #405 | `0ac80616cb723a7810acae7c945fb12721a6cf7c` | open, blocked, changes requested | independent current-head approval | -| LineageWeave | #421 | `33ec5cd521bcf861db64b9f0c1faac3b3bf4deff` | open, blocked | terminal Strix result and independent review | +| LineageWeave | #405 | `0ac80616cb723a7810acae7c945fb12721a6cf7c` | open, blocked, changes requested, auto-merge armed | independent current-head approval | +| LineageWeave | #421 | `33ec5cd521bcf861db64b9f0c1faac3b3bf4deff` | open, blocked, auto-merge armed | terminal Strix result and independent review | | LineageWeave | #426 | `11a60b370d7b5783733febb593e8f91678cc403d` | open, blocked, review required, auto-merge armed | independent current-head approval; current checks are terminal-success | -| LineageWeave | #468 | `48c7ec09d282e96b411e1060ea4ef1a769893ef9` | open, blocked | current-head protected checks and independent review | +| LineageWeave | #468 | `48c7ec09d282e96b411e1060ea4ef1a769893ef9` | open, blocked, auto-merge armed | current-head protected checks and independent review | | ContextualWisdomLab/.github | #1248 | `3f78370f3ad01409c7b2fcfb63dfb66862098fa6` | open, blocked | protected checks and independent review for the Strix scope repair | PR #464 merged into its stacked base as From bcd881c83cae71ec28509fa1b06de84a488c9616 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 18:18:22 +0900 Subject: [PATCH 5/5] 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 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. --- frontend/src/App.test.tsx | 3 +++ frontend/src/App.tsx | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/frontend/src/App.test.tsx b/frontend/src/App.test.tsx index 7462abd2c..70eb27590 100644 --- a/frontend/src/App.test.tsx +++ b/frontend/src/App.test.tsx @@ -41,6 +41,9 @@ describe("App, unauthenticated", () => { state: expect.objectContaining({ returnUrl: expect.stringMatching(/^\//) }), }), ); + // Persisted as a fallback in case the OIDC state round-trip is dropped + // (see oidcReturnUrl.ts's restoreOidcReturnUrl, consumed in main.tsx). + expect(window.sessionStorage.getItem("lineageweave.oidc.returnUrl")).toMatch(/^\//); }); }); diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 6fba0dd41..1b5b351ab 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -4610,7 +4610,8 @@ export default function App({ showLabPanels = false }: { showLabPanels?: boolean
- {destination === "admin" ? : null}